.NET- এ কী কেবল পঠনযোগ্য জেনেরিক অভিধান উপলব্ধ?


185

আমি আমার পঠনযোগ্য সম্পত্তিতে একটি অভিধানের রেফারেন্স ফিরিয়ে দিচ্ছি। আমি কীভাবে গ্রাহকদের আমার ডেটা পরিবর্তন করতে বাধা দেব? যদি এটি হয় তবে IListআমি কেবল এটি ফিরিয়ে দিতে পারতাম AsReadOnly। অভিধানের সাথে কি এমন কিছু করতে পারি?

Private _mydictionary As Dictionary(Of String, String)
Public ReadOnly Property MyDictionary() As Dictionary(Of String, String)
    Get
        Return _mydictionary
    End Get
End Property

4
এখন পর্যন্ত, এরকম কিছু উপায় হতে হবে বা অন্য সেখানে IDictionary একটি IsReadOnly সম্পত্তি হবে না ... ( msdn.microsoft.com/en-us/library/bb338949.aspx )
Powerlord

2
অপরিবর্তনীয়তার অনেকগুলি ধারণাগত সুবিধা রানটাইম প্রয়োগ না করেই লাভ করা যায়। যদি এটি একটি বেসরকারী প্রকল্প হয় তবে একটি শৃঙ্খলাবদ্ধ, অনানুষ্ঠানিক পদ্ধতিটি বিবেচনা করুন। আপনার যদি অবশ্যই কোনও ভোক্তাকে ডেটা সরবরাহ করতে হয় তবে আপনার গভীর কপিগুলি গুরুত্ব সহকারে বিবেচনা করা উচিত। যখন আপনি বিবেচনা করেন যে কোনও পরিবর্তনযোগ্য সংগ্রহের প্রয়োজন হয় ১) সংগ্রহের অনিবার্য রেফারেন্স ২) ক্রমটি নিজেই পরিবর্তন করা রোধ করা এবং ৩) সংগ্রহের আইটেমগুলির বৈশিষ্ট্যগুলিকে সংশোধন করা রোধ করা এবং এর মধ্যে কয়েকটি প্রতিচ্ছবি দ্বারা লঙ্ঘন করা যায়, রানটাইম প্রয়োগকারী ব্যবহারিক না অথবা অবাস্তব.
স্প্রেগ

26
নেট
.৪.৫

2
এছাড়াও রয়েছে এখন মাইক্রোসফট অপরিবর্তনীয় NuGet মাধ্যমে সংগ্রহগুলি msdn.microsoft.com/en-us/library/dn385366%28v=vs.110%29.aspx
VoteCoffee

উত্তর:


156

এখানে একটি সাধারণ বাস্তবায়ন যা একটি অভিধানকে মোড় দেয়:

public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    private readonly IDictionary<TKey, TValue> _dictionary;

    public ReadOnlyDictionary()
    {
        _dictionary = new Dictionary<TKey, TValue>();
    }

    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
    {
        _dictionary = dictionary;
    }

    #region IDictionary<TKey,TValue> Members

    void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
    {
        throw ReadOnlyException();
    }

    public bool ContainsKey(TKey key)
    {
        return _dictionary.ContainsKey(key);
    }

    public ICollection<TKey> Keys
    {
        get { return _dictionary.Keys; }
    }

    bool IDictionary<TKey, TValue>.Remove(TKey key)
    {
        throw ReadOnlyException();
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        return _dictionary.TryGetValue(key, out value);
    }

    public ICollection<TValue> Values
    {
        get { return _dictionary.Values; }
    }

    public TValue this[TKey key]
    {
        get
        {
            return _dictionary[key];
        }
    }

    TValue IDictionary<TKey, TValue>.this[TKey key]
    {
        get
        {
            return this[key];
        }
        set
        {
            throw ReadOnlyException();
        }
    }

    #endregion

    #region ICollection<KeyValuePair<TKey,TValue>> Members

    void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
    {
        throw ReadOnlyException();
    }

    void ICollection<KeyValuePair<TKey, TValue>>.Clear()
    {
        throw ReadOnlyException();
    }

    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        return _dictionary.Contains(item);
    }

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        _dictionary.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return _dictionary.Count; }
    }

    public bool IsReadOnly
    {
        get { return true; }
    }

    bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
    {
        throw ReadOnlyException();
    }

    #endregion

    #region IEnumerable<KeyValuePair<TKey,TValue>> Members

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion

    private static Exception ReadOnlyException()
    {
        return new NotSupportedException("This dictionary is read-only");
    }
}

11
সম্পূর্ণ কোড পোস্ট করার জন্য +1 এবং কেবল একটি লিঙ্ক নয়, তবে আমি কৌতূহল করছি, একটি পঠনঅনলাইন অভিধানে খালি নির্মাতার বিন্দুটি কী? :-)
স্যামুয়েল নেফ

20
সেই কনস্ট্রাক্টরের দিকে নজর রাখুন। আপনি যদি পাস করা অভিধানটির একটি রেফারেন্স কপি করেন, তবে কোনও বাইরের কোডের পক্ষে আপনার "কেবল পঠনযোগ্য" অভিধানটি সংশোধন করা সম্ভব। আপনার নির্মাতার পক্ষে যুক্তির একটি পূর্ণ, গভীর অনুলিপি করা উচিত।
জিজ্ঞাসাবাদ

25
@ আসখিভস: ভাল পর্যবেক্ষণ, তবে এটি কেবলমাত্র পঠনযোগ্য প্রকারের মধ্যে মূল উল্লেখটি ব্যবহার করতে বেশিরভাগ সময় কার্যকর - আপনার ব্যক্তিগত ভেরিয়েবলটি আসল রাখুন এবং বাইরের গ্রাহকদের জন্য এটি পরিবর্তন করুন। উদাহরণস্বরূপ, কেবলমাত্র ReadOnlyOserservable Colલેક્શન বা অন্তর্নির্মিত ReadOnly সংগ্রহ সংগ্রহ অবজেক্টগুলি দেখুন: থমাস এমন কিছু সরবরাহ করেছিল যা। নেট ফ্রেমওয়ার্কের অন্তর্নিহিতগুলির মতো ঠিক কাজ করে। থমাস ধন্যবাদ! +1
ম্যাট ডেক্রে

13
@ ব্যবহারকারী420667: যেভাবে এটি প্রয়োগ করা হয়েছে, এটি "কেবলমাত্র পঠনযোগ্য নয়-কেবল অভিধানের পঠনযোগ্য দর্শন"। কিছু অন্যান্য কোড মূল অভিধানের বিষয়বস্তু পরিবর্তন করতে পারে এবং এই পরিবর্তনগুলি কেবল পঠনযোগ্য অভিধানে প্রতিফলিত হবে। আপনি কী অর্জন করতে চান তার উপর নির্ভর করে এটি পছন্দসই আচরণ হতে পারে, নাও হতে পারে ...
টমাস লেভস্ক

6
@ থমাস: এটি নেট নেট বিসিএলে রিডইনলি সংগ্রহের সমান। এটি সম্ভবত একটি পরিবর্তনীয় সংগ্রহের পঠনযোগ্য দর্শন। কেবলমাত্র পঠন মানেই অপরিবর্তনীয় এবং অপরিবর্তনীয়তা আশা করা উচিত নয়।
জেফ ইয়েটস

229

.NET 4.5

.NET ফ্রেমওয়ার্ক 4.5 বিসিএল পরিচয় করিয়েছে ReadOnlyDictionary<TKey, TValue>( উত্স )।

.NET ফ্রেমওয়ার্ক 4.5 বিসিএল AsReadOnlyঅভিধানের জন্য একটি অন্তর্ভুক্ত না করায় আপনাকে নিজের লেখা (যদি আপনি এটি চান) লিখতে হবে। এটি নীচের মতো কিছু হবে, সরলতা যার মূলত এটি হাইলাইট করে যে এটি .NET 4.5 এর জন্য অগ্রাধিকার কেন নয়।

public static ReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(
    this IDictionary<TKey, TValue> dictionary)
{
    return new ReadOnlyDictionary<TKey, TValue>(dictionary);
}

.NET 4.0 এবং নীচে

.NET 4.5 এর আগে, কোনও নেট নেট ফ্রেমওয়ার্ক ক্লাস নেই যা ReadOnly Colલેક્શનেরDictionary<TKey, TValue> মতো কোনও তালিকা মোড় করে । তবে এটি তৈরি করা কঠিন নয়।

এখানে একটি উদাহরণ রয়েছে - আপনি আরও পড়ুন কেবলমাত্র পাঠ্য অভিধানের জন্য গুগল


7
এগুলি দেখে মনে হচ্ছে না যে তারা AsReadOnly()সাধারণত কোনও পদ্ধতি তৈরির কথা মনে রেখেছিল Dictionary<,>, তাই আমি ভাবছি যে কত লোক তাদের নতুন প্রকার আবিষ্কার করবে। যদিও এই স্ট্যাক ওভারফ্লো থ্রেডটি সহায়তা করবে।
জেপ্প স্টিগ নীলসেন

@ জেপ্প: আমি মনে করি এটির মনে রাখার সাথে কোনও সম্পর্ক আছে। প্রতিটি বৈশিষ্ট্যের জন্য ব্যয় হয় এবং আমি সন্দেহ করি যে AsReadOnly অগ্রাধিকার তালিকায় বেশি ছিল, বিশেষত যেহেতু এটি লেখা এত সহজ।
জেফ ইয়েটস

1
মনে রাখবেন যে এটি কেবল একটি মোড়ক; অন্তর্নিহিত অভিধানে পরিবর্তনগুলি (কনস্ট্রাক্টরের কাছে পাস করা) এখনও পঠনযোগ্য অভিধানকে পরিবর্তন করতে পারে। আরও দেখুন stackoverflow.com/questions/139592/...
TrueWill

1
@ জেফইটস এটি কতটা সহজ তা বিবেচনা করে লেখার সময়টি ব্যয় করা উচিত কি না তা সিদ্ধান্ত নেওয়ার চেয়ে কম সময় লাগত। যে কারণে, আমার বাজি "তারা ভুলে গেছে" চালু আছে।
ড্যান বেচার্ড

ট্রুউইল যেমন বলেছেন, অন্তর্নিহিত অভিধানটি এখনও পরিবর্তিত হতে পারে। আপনি যদি সত্যিকারের অপরিবর্তনযোগ্যতা চান (মূল এবং মানের
ধরণটিও পরিবর্তনযোগ্য নয় ধরে নিই

19

সাম্প্রতিক বিল্ড সম্মেলনে এটি ঘোষণা করা হয়েছিল যে নেট .৪.৫ থেকে ইন্টারফেসটি System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>অন্তর্ভুক্ত রয়েছে। প্রমাণটি এখানে (মনো) এবং এখানে (মাইক্রোসফ্ট);)

ReadOnlyDictionaryখুব বেশি অন্তর্ভুক্ত করা হয়েছে কিনা তা নিশ্চিত নন তবে কমপক্ষে ইন্টারফেসের মাধ্যমে এখন এমন একটি বাস্তবায়ন তৈরি করা কঠিন হওয়া উচিত নয় যা কোনও অফিসিয়াল। নেট জেনেরিক ইন্টারফেস প্রকাশ করে :)


5
ReadOnlyDictionary<TKey, TValue>(নেট 4.5) - msdn.microsoft.com/en-us/library/gg712875.aspx
myermian

18

আমার সহজ মোড়ক ব্যবহার করতে নির্দ্বিধায়। এটি আইডোরিওর প্রয়োগ করে না, সুতরাং অভিধানের যে পদ্ধতিগুলি বদলাবে তার জন্য রানটাইমের সময় ব্যতিক্রম ছোঁড়াতে হবে না। পরিবর্তন পদ্ধতি সহজভাবে সেখানে নেই। এর জন্য আমি আমার নিজস্ব ইন্টারফেস তৈরি করেছি যার নাম আইআরইডঅনলি ডিকোরিয়াম।

public interface IReadOnlyDictionary<TKey, TValue> : IEnumerable
{
    bool ContainsKey(TKey key);
    ICollection<TKey> Keys { get; }
    ICollection<TValue> Values { get; }
    int Count { get; }
    bool TryGetValue(TKey key, out TValue value);
    TValue this[TKey key] { get; }
    bool Contains(KeyValuePair<TKey, TValue> item);
    void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex);
    IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator();
}

public class ReadOnlyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>
{
    readonly IDictionary<TKey, TValue> _dictionary;
    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
    {
        _dictionary = dictionary;
    }
    public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); }
    public ICollection<TKey> Keys { get { return _dictionary.Keys; } }
    public bool TryGetValue(TKey key, out TValue value) { return _dictionary.TryGetValue(key, out value); }
    public ICollection<TValue> Values { get { return _dictionary.Values; } }
    public TValue this[TKey key] { get { return _dictionary[key]; } }
    public bool Contains(KeyValuePair<TKey, TValue> item) { return _dictionary.Contains(item); }
    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { _dictionary.CopyTo(array, arrayIndex); }
    public int Count { get { return _dictionary.Count; } }
    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return _dictionary.GetEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator() { return _dictionary.GetEnumerator(); }
}

4
IDictionaryচুক্তি লঙ্ঘন না করার জন্য +1 । আমি মনে করি যে IDictionaryউত্তরাধিকার সূত্রে প্রাপ্ত হওয়ার জন্য এটি কোনও ওওপি দৃষ্টিভঙ্গি থেকে আরও সঠিক IReadOnlyDictionary
স্যাম

@ সাম সম্মত হয়েছেন, এবং আমরা যদি ফিরে যেতে পারি তবে আমি মনে করি IDictionary(বর্তমানের জন্য IReadOnlyDictionary) এবং IMutableDictionary(বর্তমানের জন্য ) থাকা ভাল এবং সবচেয়ে সঠিক হবে IDictionary
মাস্টারমাস্টিক

1
@ মাস্টারমাস্টিক এটি একটি উদ্ভট প্রস্তাব। বিপরীত ধারনাটির উপর নির্ভর করে অন্য কোনও অন্তর্নির্মিত শ্রেণিগুলি আমি স্মরণ করি না যে একজন অপরিবর্তনীয় সংগ্রহ যা ব্যবহারকারী কোনও ডিফল্টরূপে প্রত্যাশা করে।
ড্যান বেচার্ড

11

IsReadOnly on IDictionary<TKey,TValue>থেকে উত্তরাধিকার সূত্রে প্রাপ্ত ICollection<T>( হিসাবে IDictionary<TKey,TValue>প্রসারিত )। এটি কোনওভাবেই ব্যবহার বা প্রয়োগ করা হয় না (এবং প্রকৃতপক্ষে সম্পর্কিত সদস্যদের সুস্পষ্টভাবে প্রয়োগের মাধ্যমে এটি "লুকানো" )।ICollection<T>ICollection<KeyValuePair<TKey,TValue>>ICollection<T>

সমস্যাটি সমাধান করার জন্য কমপক্ষে 3 টি উপায় দেখতে পাচ্ছি:

  1. কেবলমাত্র একটি কাস্টম পঠন কার্যকর করুন IDictionary<TKey, TValue>এবং প্রস্তাবিত হিসাবে একটি অভ্যন্তরীণ অভিধানে মোড়ানো / প্রতিনিধি করুন
  2. ICollection<KeyValuePair<TKey, TValue>>কেবল পঠন হিসাবে মান সেট বা IEnumerable<KeyValuePair<TKey, TValue>>মান ব্যবহারের উপর নির্ভর করে একটি সেট প্রদান করুন
  3. অনুলিপি নির্মাণকারীকে ব্যবহার করে অভিধানটি ক্লোন করুন .ctor(IDictionary<TKey, TValue>)এবং একটি অনুলিপি ফিরিয়ে দিন - ব্যবহারকারীরা তাদের পছন্দমতো এটি করতে মুক্ত হন এবং এটি উত্সের অভিধানটি হোস্টিংয়ের অবস্থার উপর প্রভাব ফেলবে না। নোট করুন যে অভিধানটি আপনি ক্লোনিং করছেন তাতে যদি রেফারেন্স টাইপ থাকে (উদাহরণে প্রদর্শিত স্ট্রিং না থাকে) আপনার "ম্যানুয়ালি" অনুলিপিটি করতে হবে এবং পাশাপাশি রেফারেন্সের ধরণগুলিও ক্লোন করতে হবে।

একদিকে যেমন; সংগ্রহগুলি উন্মোচিত করার সময়, সবচেয়ে ছোট সম্ভাব্য ইন্টারফেসটি উন্মোচন করার লক্ষ্য রাখুন - উদাহরণস্বরূপ এটি আইডোরিয়াস হওয়া উচিত কারণ এটি আপনাকে টাইপটি প্রকাশ করে এমন सार्वजनिक চুক্তি ভঙ্গ না করে অন্তর্নিহিত প্রয়োগকে ভিন্ন করতে দেয় implementation


8

কেবলমাত্র পঠনযোগ্য অভিধানটি কিছু পরিমাণে প্রতিস্থাপন করতে পারে Func<TKey, TValue>- আমি সাধারণত এপিআইতে এটি ব্যবহার করি যদি আমি কেবল লোকেরা অনুসন্ধান করি; এটি সহজ, এবং বিশেষত, আপনার যদি ইচ্ছা হয় তবে ব্যাকএন্ডটি প্রতিস্থাপন করা সহজ। এটি কীগুলির তালিকা সরবরাহ করে না; বিষয়টি আপনি কী করছেন তার উপর নির্ভর করে কিনা।


4

না, তবে এটি আপনার নিজের রোল করা সহজ হবে। আইডিকোরিয়াসটি একটি ইস্রাডঅনলি সম্পত্তি সংজ্ঞায়িত করে। যথাযথ পদ্ধতিগুলি থেকে কেবল একটি অভিধান মোড়ানো এবং একটি নটসপোর্টড এক্সসেপশন নিক্ষেপ করুন।


3

ছাত্রলীগে পাওয়া যায় না। তবে আমি আমার বিসিএল এক্সট্রা প্রজেক্টে একটি রিডঅনলিডিয়েশনারি (নাম ইমটুটেবল ম্যাপ) প্রকাশ করেছি

পুরোপুরি অপরিবর্তনীয় অভিধান হওয়ার পাশাপাশি এটি একটি প্রক্সি অবজেক্ট তৈরি করা সমর্থন করে যা আইডিকোয়ারী প্রয়োগ করে এবং যে কোনও জায়গায় আইডিকোরি নেওয়া হয় সেখানে ব্যবহার করা যেতে পারে। যখনই কোনও রূপান্তরকারী এপিআই কল করা হবে তখন এটি ব্যতিক্রম করবে

void Example() { 
  var map = ImmutableMap.Create<int,string>();
  map = map.Add(42,"foobar");
  IDictionary<int,string> dictionary = CollectionUtility.ToIDictionary(map);
}

9
আপনার ImmutableMap ভারসাম্যযুক্ত গাছ হিসাবে প্রয়োগ করা হয়েছে। নেট থেকে, লোকেরা সাধারণত হ্যাশিংয়ের মাধ্যমে একটি "অভিধান" বাস্তবায়িত হওয়ার প্রত্যাশা করে - এবং সংশ্লিষ্ট জটিলতার বৈশিষ্ট্যগুলি প্রদর্শন করে - আপনি "অভিধান" হিসাবে ইমিউটেবল ম্যাপ প্রচারে সতর্ক হতে চাইতে পারেন।
গ্লেন স্লেডেন

কোড.msdn.com সাইটগুলি অবরুদ্ধ বলে মনে হচ্ছে। বিসিএলসেক্সট্রাস এখন এখানে github.com/scottwis/tiny/tree/master/third-party/BclExtras
BozoJoe

1

আপনি এমন একটি শ্রেণি তৈরি করতে পারেন যা কেবল অভিধানের আংশিক বাস্তবায়ন কার্যকর করে এবং সমস্ত অ্যাড / রিমুভ / সেট ফাংশনগুলি গোপন করে।

অভ্যন্তরীণভাবে একটি অভিধান ব্যবহার করুন যাতে বাহ্যিক শ্রেণি সমস্ত অনুরোধ পাস করে।

তবে, যেহেতু আপনার অভিধানটি সম্ভবত রেফারেন্সের ধরণের ধারণাগুলি ধারণ করে, তাই অভিধানের অধীনে থাকা ক্লাসগুলিতে আপনি ব্যবহারকারীকে মান নির্ধারণ থেকে বিরত রাখার কোনও উপায় নেই (যদি না কেবল এই বিভাগগুলি কেবল পঠিত হয়)


1

আমি মনে করি না এটি করার একটি সহজ উপায় আছে ... যদি আপনার অভিধানটি একটি কাস্টম শ্রেণীর অংশ হয় তবে আপনি এটি সূচক দিয়ে অর্জন করতে পারেন:

public class MyClass
{
  private Dictionary<string, string> _myDictionary;

  public string this[string index]
  {
    get { return _myDictionary[index]; }
  }
}

আমার পুরো অভিধানের পাশাপাশি একটি সূচকও প্রকাশ করতে সক্ষম হওয়া দরকার।
রব সোবার্স

এটি খুব ভাল সমাধান বলে মনে হচ্ছে। যাইহোক, ক্লাস মাইক্লাসের ক্লায়েন্টদের অভিধানটি সম্পর্কে আরও জানা দরকার, উদাহরণস্বরূপ, এর মাধ্যমে পুনরাবৃত্তির জন্য। এবং কী কী বিদ্যমান না থাকলে (ট্রাইগেটভ্যালু () কোনও রূপে প্রকাশ করা ভাল ধারণা হতে পারে)? আপনি কি নিজের উত্তর এবং নমুনা কোডটি আরও সম্পূর্ণ করতে পারবেন?
পিটার মর্টেনসেন

1

+1 দুর্দান্ত কাজ, টমাস। আমি ReadOnlyD शब्दकोয় আরও একধাপ এগিয়ে নিয়েছি।

অনেক ডেল এর সমাধান মত, আমি সরাতে চেয়েছিলেন Add(), Clear(), Remove()IntelliSense থেকে, ইত্যাদি। তবে আমি চেয়েছিলাম আমার উদ্ভূত বস্তুগুলি প্রয়োগ করা হোক IDictionary<TKey, TValue>

তদতিরিক্ত, আমি নীচের কোডটি ভাঙ্গতে চাই: (আবার, ডেলের সমাধান এটিও করে)

ReadOnlyDictionary<int, int> test = new ReadOnlyDictionary<int,int>(new Dictionary<int, int> { { 1, 1} });
test.Add(2, 1);  //CS1061

অ্যাড () লাইন ফলাফল এতে:

error CS1061: 'System.Collections.Generic.ReadOnlyDictionary<int,int>' does not contain a definition for 'Add' and no extension method 'Add' accepting a first argument 

কলার এখনও এটিকে কাস্ট করতে পারে IDictionary<TKey, TValue>, তবে NotSupportedExceptionআপনি যদি কেবল পঠনযোগ্য সদস্যদের (টমাসের সমাধান থেকে) ব্যবহার করার চেষ্টা করেন তবে তা উত্থাপিত হবে।

যাইহোক, যে কেউ এর জন্যও আমার সমাধানটি এখানে চেয়েছিলেন:

namespace System.Collections.Generic
{
    public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
    {
        const string READ_ONLY_ERROR_MESSAGE = "This dictionary is read-only";

        protected IDictionary<TKey, TValue> _Dictionary;

        public ReadOnlyDictionary()
        {
            _Dictionary = new Dictionary<TKey, TValue>();
        }

        public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
        {
            _Dictionary = dictionary;
        }

        public bool ContainsKey(TKey key)
        {
            return _Dictionary.ContainsKey(key);
        }

        public ICollection<TKey> Keys
        {
            get { return _Dictionary.Keys; }
        }

        public bool TryGetValue(TKey key, out TValue value)
        {
            return _Dictionary.TryGetValue(key, out value);
        }

        public ICollection<TValue> Values
        {
            get { return _Dictionary.Values; }
        }

        public TValue this[TKey key]
        {
            get { return _Dictionary[key]; }
            set { throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE); }
        }

        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return _Dictionary.Contains(item);
        }

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            _Dictionary.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return _Dictionary.Count; }
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return _Dictionary.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return (_Dictionary as IEnumerable).GetEnumerator();
        }

        void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
        {
            throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
        }

        bool IDictionary<TKey, TValue>.Remove(TKey key)
        {
            throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
        }

        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
        {
            throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
        }

        void ICollection<KeyValuePair<TKey, TValue>>.Clear()
        {
            throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
        }

        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
        {
            throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
        }
    }
}


0
public IEnumerable<KeyValuePair<string, string>> MyDictionary()
{
    foreach(KeyValuePair<string, string> item in _mydictionary)
        yield return item;
}

2
বা আপনি করতে পারেন:public IEnumerable<KeyValuePair<string, string>> MyDictionary() { return _mydictionary; }
পট

0

এটি একটি খারাপ সমাধান, নীচে দেখুন।

যারা এখনও নেট নেট 4.0 ব্যবহার করেন বা তার আগে, তাদের কাছে আমার একটি ক্লাস রয়েছে যা গ্রহণযোগ্য উত্তরের মতো কাজ করে তবে এটি আরও খাটো। এটি ডিকশনারি অবজেক্টটি প্রসারিত করে, নির্দিষ্ট সদস্যদের ডেকে এনে একটি ব্যতিক্রম ছুঁড়ে দেওয়ার জন্য ওভাররাইডিং (প্রকৃতপক্ষে লুকিয়ে থাকে)।

যদি কলার অ্যাড, রিমুভ বা অন্য কোনও মিউটেশন অপারেশনটিকে বিল্ট-ইন ডিকশনারিটিতে কল করার চেষ্টা করে তবে সংকলক একটি ত্রুটি ছুঁড়ে দেবে। এই সংকলক ত্রুটিগুলি বাড়ানোর জন্য আমি অপ্রচলিত বৈশিষ্ট্যগুলি ব্যবহার করি। এইভাবে, আপনি এই রিডইনলি অভিধানের সাথে একটি অভিধান প্রতিস্থাপন করতে পারবেন এবং তাত্ক্ষণিকভাবে দেখতে পারবেন আপনার অ্যাপ্লিকেশনটি চালানো এবং রান-টাইম ব্যতিক্রমগুলির জন্য অপেক্ষা না করেই কোনও সমস্যা হতে পারে।

দেখা যাক:

public class ReadOnlyException : Exception
{
}

public class ReadOnlyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
        : base(dictionary) { }

    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
        : base(dictionary, comparer) { }

    //The following four constructors don't make sense for a read-only dictionary

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public ReadOnlyDictionary() { throw new ReadOnlyException(); }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public ReadOnlyDictionary(IEqualityComparer<TKey> comparer) { throw new ReadOnlyException(); }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public ReadOnlyDictionary(int capacity) { throw new ReadOnlyException(); }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public ReadOnlyDictionary(int capacity, IEqualityComparer<TKey> comparer) { throw new ReadOnlyException(); }


    //Use hiding to override the behavior of the following four members
    public new TValue this[TKey key]
    {
        get { return base[key]; }
        //The lack of a set accessor hides the Dictionary.this[] setter
    }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public new void Add(TKey key, TValue value) { throw new ReadOnlyException(); }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public new void Clear() { throw new ReadOnlyException(); }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public new bool Remove(TKey key) { throw new ReadOnlyException(); }
}

এই সমাধানটির এখানে @ সুপের্যাট দ্বারা চিত্রিত একটি সমস্যা রয়েছে:

var dict = new Dictionary<int, string>
{
    { 1, "one" },
    { 2, "two" },
    { 3, "three" },
};

var rodict = new ReadOnlyDictionary<int, string>(dict);
var rwdict = rodict as Dictionary<int, string>;
rwdict.Add(4, "four");

foreach (var item in rodict)
{
    Console.WriteLine("{0}, {1}", item.Key, item.Value);
}

আমার প্রত্যাশার মতো একটি সংকলন-সময় ত্রুটি দেওয়া বা আমি যেমন আশা করি একটি রানটাইম-ব্যতিক্রম না দিয়ে এই কোডটি ত্রুটি ছাড়াই চলে। এটি চারটি সংখ্যা প্রিন্ট করে। এটি আমার রিডঅনলি ডিকোরিয়েন্সিটিকে একটি রিডরাইটডিয়েশনারি করে তোলে।


এই পদ্ধতির সাথে সমস্যাটি হ'ল এই ধরণের অবজেক্টটি এমন কোনও পদ্ধতিতে প্রেরণ করা যেতে পারে যা Dictionary<TKey,TValue>কোনও সংকলক অভিযোগ ছাড়াই প্রত্যাশা করে এবং প্লেইন-ডিকশনারি টাইপের প্রসঙ্গকে কাস্টিং বা জোর করা কোনও সুরক্ষা সরিয়ে ফেলবে।
সুপারক্যাট

@ সুপের্যাট, বাজে, তুমি ঠিক বলেছ। আমি ভেবেছিলাম আমারও ভাল সমাধান হয়েছে।
ব্যবহারকারী 2023861

আমি একটি অমৌলিক উপার্জন স্মরণ Dictionaryএকটি সঙ্গে Cloneপদ্ধতি যে শৃঙ্খলিত MemberwiseClone। দুর্ভাগ্যক্রমে, ব্যাকিং স্টোরগুলিকে ক্লোনিং করে দক্ষতার সাথে অভিধানের ক্লোন করা সম্ভব হওয়া উচিত, ব্যাকিং স্টোরগুলি বোঝার privateপরিবর্তে protectedএর অর্থ হ'ল কোনও উত্পন্ন শ্রেণীর পক্ষে ক্লোন করার কোনও উপায় নেই; MemberwiseCloneব্যাকিং স্টোরগুলিকে ক্লোনিং না করেই ব্যবহার করার অর্থ আসল অভিধানে পরবর্তীকৃত পরিবর্তনগুলি ক্লোনটি ভেঙে দেবে এবং ক্লোনটিতে করা পরিবর্তনগুলি মূলটি ভেঙে দেবে।
সুপারক্যাট 14'15
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.