Apakah ada kamus umum baca-saja yang tersedia di .NET?

186

Saya mengembalikan referensi ke kamus di properti hanya baca saya. Bagaimana cara mencegah konsumen mengubah data saya? Jika ini adalah IListsaya hanya bisa mengembalikannya AsReadOnly. Apakah ada hal serupa yang dapat saya lakukan dengan kamus?

Private _mydictionary As Dictionary(Of String, String)
Public ReadOnly Property MyDictionary() As Dictionary(Of String, String)
    Get
        Return _mydictionary
    End Get
End Property
Rob Sobers
sumber
4
Pasti ada cara untuk melakukannya, atau tidak ada properti IsReadOnly di IDictionary ... ( msdn.microsoft.com/en-us/library/bb338949.aspx )
Powerlord
2
Banyak manfaat konseptual dari kekekalan dapat diperoleh tanpa menjalankan runtime. Jika ini adalah proyek pribadi, pertimbangkan metode yang disiplin dan informal. Jika Anda harus memberikan data kepada konsumen, Anda harus secara serius mempertimbangkan salinan yang dalam. Ketika Anda menganggap bahwa koleksi yang tidak dapat diubah memerlukan 1) referensi yang tidak dapat diubah untuk koleksi 2) mencegah mutasi urutan itu sendiri dan 3) mencegah memodifikasi properti pada item koleksi, dan bahwa beberapa di antaranya dapat dilanggar oleh refleksi, pelaksanaan runtime adalah tidak praktis.
Sprague
27
Sejak .NET 4.5, Ada System.Collections.ObjectModel.ReadOnlyDictionary ^ _ ^
Smartkid
2
Sekarang juga ada Microsoft Immutable Collections melalui NuGet msdn.microsoft.com/en-us/library/dn385366%28v=vs.110%29.aspx
VoteCoffee

Jawaban:

156

Berikut ini adalah implementasi sederhana yang membungkus kamus:

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");
    }
}
Thomas Levesque
sumber
11
+1 untuk memposting kode lengkap dan bukan hanya tautan, tapi saya ingin tahu, apa gunanya konstruktor kosong di ReadOnlyDictionary? :-)
Samuel Neff
20
Hati-hati dengan konstruktor itu. Jika Anda membuat salinan referensi dari kamus yang dikirimkan, mungkin saja sepotong kode dari luar mengubah kamus Anda "Hanya Baca". Konstruktor Anda harus melakukan salinan argumen yang lengkap dan mendalam.
askheaves
25
@askheaves: Pengamatan yang baik, tetapi sebenarnya cukup sering berguna untuk menggunakan referensi asli pada tipe Read Only - simpan variabel pribadi Anda yang asli dan modifikasi untuk konsumen luar. Misalnya, periksa objek ReadOnlyObservableCollection atau ReadOnlyCollection yang dibangun: Thomas memberikan sesuatu yang bekerja persis seperti yang melekat pada kerangka .Net. Thomas terima kasih! +1
Matt DeKrey
13
@ user420667: cara penerapannya, ini merupakan "tampilan hanya baca dari kamus yang tidak hanya baca". Beberapa kode lain mungkin mengubah konten kamus asli, dan perubahan ini akan tercermin dalam kamus hanya baca. Bisa jadi perilaku yang diinginkan, atau tidak, tergantung pada apa yang ingin Anda capai ...
Thomas Levesque
6
@ Thomas: Itu sama dengan ReadOnlyCollection di .NET BCL. Ini adalah tampilan hanya baca pada koleksi yang mungkin bisa diubah. ReadOnly bukan berarti kekekalan dan kekekalan seharusnya tidak diharapkan.
Jeff Yates
229

.NET 4.5

.NET Framework 4.5 BCL memperkenalkan ReadOnlyDictionary<TKey, TValue>( sumber ).

Karena .NET Framework 4.5 BCL tidak menyertakan AsReadOnlykamus, Anda harus menulis sendiri (jika Anda menginginkannya). Ini akan menjadi sesuatu seperti yang berikut, kesederhanaan yang mungkin menyoroti mengapa itu bukan prioritas untuk .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 dan di bawah

Sebelum .NET 4.5, tidak ada kelas .NET framework yang membungkus Dictionary<TKey, TValue>seperti ReadOnlyCollection membungkus Daftar . Namun, tidak sulit untuk membuatnya.

Berikut ini adalah contoh - ada banyak lainnya jika Anda Google untuk ReadOnlyDictionary .

Jeff Yates
sumber
7
Sepertinya mereka tidak ingat untuk membuat AsReadOnly()metode seperti biasa Dictionary<,>, jadi saya ingin tahu berapa banyak orang yang akan menemukan tipe baru mereka. Thread Stack Overflow ini akan membantu.
Jeppe Stig Nielsen
@Jeppe: Saya ragu ada hubungannya dengan mengingat. Setiap fitur berharga dan saya ragu AsReadOnly berada di urutan teratas, terutama karena begitu mudah untuk menulis.
Jeff Yates
1
Perhatikan bahwa ini hanyalah pembungkus; perubahan pada kamus yang mendasarinya (kamus yang diteruskan ke konstruktor) masih akan mengubah kamus hanya-baca. Lihat juga stackoverflow.com/questions/139592/…
TrueWill
1
@ JeffYates Mempertimbangkan betapa sederhananya, menulis itu akan memakan waktu lebih sedikit daripada memutuskan apakah akan menghabiskan waktu untuk menulisnya atau tidak. Karena itu, taruhan saya ada pada "mereka lupa".
Dan Bechard
Seperti yang dikatakan TrueWill, kamus yang mendasarinya masih bisa dimutasi. Anda mungkin ingin mempertimbangkan untuk mengirimkan klon kamus asli ke konstruktor jika Anda ingin kekekalan yang sebenarnya (dengan asumsi kunci dan tipe nilai juga tidak dapat diubah.)
user420667
19

Diumumkan dalam konferensi BUILD baru-baru ini bahwa sejak .NET 4.5, antarmuka System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>disertakan. Buktinya ada di sini (Mono) dan di sini (Microsoft);)

Tidak yakin jika ReadOnlyDictionarydisertakan juga, tetapi setidaknya dengan antarmuka itu seharusnya tidak sulit untuk membuat sekarang implementasi yang memperlihatkan antarmuka .NET generik resmi :)

knocte
sumber
5
ReadOnlyDictionary<TKey, TValue>(.Net 4.5) - msdn.microsoft.com/en-us/library/gg712875.aspx
myermian
18

Jangan ragu untuk menggunakan pembungkus sederhana saya. Ini TIDAK mengimplementasikan IDictionary, sehingga tidak harus membuang pengecualian saat runtime untuk metode kamus yang akan mengubah kamus. Ubah metode sama sekali tidak ada. Saya membuat antarmuka saya sendiri untuk itu yang disebut IReadOnlyDictionary.

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(); }
}
Dale Barnard
sumber
4
+1 karena tidak melanggar IDictionarykontrak. Saya pikir itu lebih benar dari perspektif OOP untuk IDictionarydiwarisi dari IReadOnlyDictionary.
Sam
@ Sam Setuju, dan jika kita bisa kembali, saya pikir itu akan menjadi yang terbaik dan paling benar untuk memiliki IDictionary(untuk saat ini IReadOnlyDictionary) dan IMutableDictionary(untuk saat ini IDictionary).
MasterMastic
1
@MasterMastic Itu proposisi aneh. Saya tidak ingat kelas bawaan lainnya yang mengandalkan asumsi terbalik bahwa koleksi yang tidak dapat diubah adalah yang diharapkan oleh pengguna secara default.
Dan Bechard
11

IsReadOnly on IDictionary<TKey,TValue>diwarisi dari ICollection<T>( IDictionary<TKey,TValue>extends ICollection<T>as ICollection<KeyValuePair<TKey,TValue>>). Itu tidak digunakan atau diimplementasikan dengan cara apa pun (dan sebenarnya "tersembunyi" melalui penggunaan secara eksplisit menerapkan ICollection<T>anggota terkait ).

Setidaknya ada 3 cara yang bisa saya lihat untuk menyelesaikan masalah:

  1. Terapkan custom read only IDictionary<TKey, TValue>dan bungkus / delegasikan ke kamus dalam seperti yang disarankan
  2. Kembalikan satu ICollection<KeyValuePair<TKey, TValue>>set sebagai hanya baca atau IEnumerable<KeyValuePair<TKey, TValue>>tergantung pada penggunaan nilai
  3. Mengkloning kamus menggunakan copy constructor .ctor(IDictionary<TKey, TValue>)dan mengembalikan salinan - dengan cara itu pengguna bebas untuk melakukannya sesuka mereka dan itu tidak berdampak pada keadaan objek hosting kamus sumber. Perhatikan bahwa jika kamus yang Anda kloning berisi jenis referensi (bukan string seperti yang ditunjukkan dalam contoh) Anda perlu menyalinnya secara "manual" dan mengkloning jenis referensi juga.

Sebagai samping; ketika mengekspos koleksi, bertujuan untuk mengekspos antarmuka sekecil mungkin - dalam contoh kasus itu harus IDictionary karena ini memungkinkan Anda untuk memvariasikan implementasi yang mendasarinya tanpa melanggar kontrak publik yang diekspos oleh tipe tersebut.

Neal
sumber
8

Kamus read-only sampai batas tertentu dapat diganti dengan Func<TKey, TValue>- Saya biasanya menggunakan ini dalam API jika saya hanya ingin orang yang melakukan pencarian; itu sederhana, dan khususnya, mudah untuk mengganti backend jika Anda ingin. Namun, itu tidak memberikan daftar kunci; apakah itu penting tergantung pada apa yang Anda lakukan.

Eamon Nerbonne
sumber
4

Tidak, tetapi akan mudah untuk menggulung sendiri. IDictionary mendefinisikan properti IsReadOnly. Hanya membungkus Kamus dan melempar NotSupportedException dari metode yang sesuai.

minggu lalu
sumber
3

Tidak ada yang tersedia di BCL. Namun saya menerbitkan ReadOnlyDictionary (bernama ImmutableMap) di Proyek BCL Extras saya

Selain menjadi kamus yang sepenuhnya tidak dapat diubah, kamus ini juga mendukung pembuatan objek proxy yang mengimplementasikan IDictionary dan dapat digunakan di mana pun tempat IDictionary diambil. Ini akan mengeluarkan pengecualian setiap kali salah satu API yang bermutasi dipanggil

void Example() { 
  var map = ImmutableMap.Create<int,string>();
  map = map.Add(42,"foobar");
  IDictionary<int,string> dictionary = CollectionUtility.ToIDictionary(map);
}
JaredPar
sumber
9
ImmutableMap Anda diimplementasikan sebagai pohon seimbang. Karena, di .NET, orang umumnya mengharapkan "kamus" diimplementasikan melalui hashing - dan menunjukkan properti kompleksitas yang sesuai - Anda mungkin ingin berhati-hati mempromosikan ImmutableMap sebagai "kamus."
Glenn Slayden
Tampaknya situs code.msdn.com tidak berfungsi. BCLextras sekarang di sini github.com/scottwis/tiny/tree/master/third-party/BclExtras
BozoJoe
1

Anda bisa membuat kelas yang hanya mengimplementasikan sebagian implementasi kamus, dan menyembunyikan semua fungsi add / remove / set.

Gunakan kamus secara internal bahwa kelas eksternal melewati semua permintaan.

Namun, karena kamus Anda kemungkinan memegang jenis referensi, tidak mungkin Anda dapat menghentikan pengguna dari menetapkan nilai pada kelas yang dipegang oleh kamus (kecuali jika kelas itu sendiri hanya dibaca)

Jason Coyne
sumber
1

Saya rasa tidak ada cara mudah untuk melakukannya ... jika kamus Anda adalah bagian dari kelas khusus, Anda dapat mencapainya dengan pengindeks:

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

  public string this[string index]
  {
    get { return _myDictionary[index]; }
  }
}
Jonas
sumber
Saya harus dapat mengekspos seluruh kamus serta pengindeks.
Rob Sobers
Ini sepertinya solusi yang sangat bagus. Namun, klien kelas MyClass mungkin perlu tahu lebih banyak tentang kamus, misalnya, untuk iterasi melaluinya. Dan bagaimana jika kunci tidak ada (mungkin mengekspos TryGetValue () dalam beberapa bentuk menjadi ide yang baik)? Bisakah Anda membuat jawaban dan kode sampel Anda lebih lengkap?
Peter Mortensen
1

+1 Pekerjaan bagus, Thomas. Saya mengambil ReadOnlyDictionary selangkah lebih maju.

Sama seperti solusi Dale, saya ingin menghapus Add(), Clear(), Remove(), dll dari IntelliSense. Tapi saya ingin objek turunan saya diimplementasikan IDictionary<TKey, TValue>.

Selain itu, saya ingin kode berikut untuk dipecah: (Sekali lagi, solusi Dale juga melakukan ini)

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

Baris Tambahkan () menghasilkan:

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

Penelepon masih dapat IDictionary<TKey, TValue>mengirimkannya, tetapi NotSupportedExceptionakan dimunculkan jika Anda mencoba menggunakan anggota yang tidak hanya baca (dari solusi Thomas).

Bagaimanapun, inilah solusi saya untuk siapa saja yang juga menginginkan ini:

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);
        }
    }
}
Robert H.
sumber
0
public IEnumerable<KeyValuePair<string, string>> MyDictionary()
{
    foreach(KeyValuePair<string, string> item in _mydictionary)
        yield return item;
}
shahkalpesh
sumber
2
Atau Anda dapat melakukannya:public IEnumerable<KeyValuePair<string, string>> MyDictionary() { return _mydictionary; }
Pat
0

Ini adalah solusi yang buruk, lihat di bagian bawah.

Bagi mereka yang masih menggunakan .NET 4.0 atau sebelumnya, saya memiliki kelas yang berfungsi seperti yang ada di jawaban yang diterima, tetapi jauh lebih pendek. Itu memperluas objek Kamus yang ada, menimpa (sebenarnya menyembunyikan) anggota tertentu agar mereka melemparkan pengecualian saat dipanggil.

Jika pemanggil mencoba memanggil Tambah, Hapus, atau operasi mutasi lain yang dimiliki Kamus bawaan, kompiler akan membuat kesalahan. Saya menggunakan atribut Usang untuk meningkatkan kesalahan kompilator ini. Dengan cara ini, Anda dapat mengganti Kamus dengan ReadOnlyDictionary ini dan segera melihat di mana masalah mungkin tanpa harus menjalankan aplikasi Anda dan menunggu pengecualian run-time.

Lihatlah:

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(); }
}

Solusi ini memiliki masalah yang ditunjukkan oleh @supercat yang diilustrasikan di sini:

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);
}

Daripada memberikan kesalahan waktu kompilasi seperti yang saya harapkan, atau pengecualian runtime seperti yang saya harapkan, kode ini berjalan tanpa kesalahan. Mencetak empat angka. Itu membuat ReadOnlyDictionary saya menjadi ReadWriteDictionary.

pengguna2023861
sumber
Masalah dengan pendekatan itu adalah bahwa objek seperti itu dapat diteruskan ke metode yang mengharapkan Dictionary<TKey,TValue>tanpa kompiler komplain, dan melemparkan atau memaksa referensi ke tipe kamus sederhana akan menghapus perlindungan apa pun.
supercat
@ supercat, sial, kau benar. Saya pikir saya punya solusi yang bagus juga.
user2023861
Saya ingat membuat turunan Dictionarydengan Clonemetode yang dirantai MemberwiseClone. Sayangnya, walaupun harus dimungkinkan untuk mengkloning kamus secara efisien dengan mengkloning toko-toko pendukung, fakta bahwa toko-toko pendukung privatebukan protectedberarti tidak ada cara bagi kelas turunan untuk mengkloning mereka; menggunakan MemberwiseClonetanpa juga mengkloning toko dukungan akan berarti bahwa modifikasi berikutnya yang dibuat untuk kamus asli akan merusak klon, dan modifikasi yang dilakukan pada klon akan merusak yang asli.
supercat