Esta é uma solução ruim, veja abaixo.
Para aqueles que ainda usam o .NET 4.0 ou anterior, tenho uma classe que funciona exatamente como a da resposta aceita, mas é muito mais curta. Ele estende o objeto Dicionário existente, substituindo (na verdade ocultando) determinados membros para que eles gerem uma exceção quando chamados.
Se o chamador tentar chamar Adicionar, Remover ou alguma outra operação de mutação que o Dicionário interno possui, o compilador lançará um erro. Eu uso os atributos obsoletos para gerar esses erros do compilador. Dessa maneira, você pode substituir um Dicionário por este ReadOnlyDictionary e ver imediatamente onde estão os problemas sem precisar executar o aplicativo e aguardar exceções em tempo de execução.
Dê uma olhada:
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(); }
}
Esta solução tem um problema apontado por @supercat ilustrado aqui:
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);
}
Em vez de fornecer um erro em tempo de compilação, como eu esperava, ou uma exceção de tempo de execução, como eu esperava, esse código é executado sem erros. Imprime quatro números. Isso faz do meu ReadOnlyDictionary um ReadWriteDictionary.