我正在尝试公开一个只读字典,该字典包含具有只读接口的对象。在内部,字典是可写的,其中的对象也是可写的(参见下面的示例代码)。我的问题是,由于问题here中概述的原因,IReadOnlyDictionary不支持协变转换。这意味着我不能将我的内部字典公开为只读字典。
所以我的问题是,有没有一种有效的方法将我的内部字典转换为IReadOnlyDictionary,或者其他一些方法来处理它?我能想到的选择是:
public class ExposesReadOnly
{
private Dictionary<int, NotReadOnly> InternalDict { get; set; }
public IReadOnlyDictionary<int, IReadOnly> PublicList
{
get
{
// This doesn't work...
return this.InternalDict;
}
}
// This class can be modified internally, but I don't want
// to expose this functionality.
private class NotReadOnly : IReadOnly
{
public string Name { get; set; }
}
}
public interface IReadOnly
{
string Name { get; }
}
答案 0 :(得分:15)
您可以为字典编写自己的只读包装器,例如:
public class ReadOnlyDictionaryWrapper<TKey, TValue, TReadOnlyValue> : IReadOnlyDictionary<TKey, TReadOnlyValue> where TValue : TReadOnlyValue
{
private IDictionary<TKey, TValue> _dictionary;
public ReadOnlyDictionaryWrapper(IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null) throw new ArgumentNullException("dictionary");
_dictionary = dictionary;
}
public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); }
public IEnumerable<TKey> Keys { get { return _dictionary.Keys; } }
public bool TryGetValue(TKey key, out TReadOnlyValue value)
{
TValue v;
var result = _dictionary.TryGetValue(key, out v);
value = v;
return result;
}
public IEnumerable<TReadOnlyValue> Values { get { return _dictionary.Values.Cast<TReadOnlyValue>(); } }
public TReadOnlyValue this[TKey key] { get { return _dictionary[key]; } }
public int Count { get { return _dictionary.Count; } }
public IEnumerator<KeyValuePair<TKey, TReadOnlyValue>> GetEnumerator()
{
return _dictionary
.Select(x => new KeyValuePair<TKey, TReadOnlyValue>(x.Key, x.Value))
.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
答案 1 :(得分:1)
我建议您可能希望定义自己的协变接口,并包含协变访问方法以及创建只读包装器对象的方法,该对象实现IDictionary
或IReadonlyDictionary
与所需的类型。只需忽略界面中的IEnumerable<KeyValuePair<TKey,TValue>>
即可。
根据您正在做的事情,定义由IFetchByKey<out TValue>
继承的IFetchByKey<in TKey, out TValue>
可能会有所帮助,前者接受任何类型对象的查询(给定对象实例,a Cat
的集合应该能够说明它是否包含该实例,即使它是类型Dog
或ToyotaPrius
;该集合将不包含后者类型的任何实例,并且应该能说出来。)
答案 2 :(得分:0)
也许这个解决方案适合您:
public class ExposesReadOnly
{
private IDictionary<int, IReadOnly> InternalDict { get; set; }
public IReadOnlyDictionary<int, IReadOnly> PublicList
{
get
{
IReadOnlyDictionary<int, IReadOnly> dictionary = new ReadOnlyDictionary<int, IReadOnly>(InternalDict);
return dictionary;
}
}
private class NotReadOnly : IReadOnly
{
public string Name { get; set; }
}
public void AddSomeValue()
{
InternalDict = new Dictionary<int, NotReadOnly>();
InternalDict.Add(1, new NotReadOnly() { Name = "SomeValue" });
}
}
public interface IReadOnly
{
string Name { get; }
}
class Program
{
static void Main(string[] args)
{
ExposesReadOnly exposesReadOnly = new ExposesReadOnly();
exposesReadOnly.AddSomeValue();
Console.WriteLine(exposesReadOnly.PublicList[1].Name);
Console.ReadLine();
exposesReadOnly.PublicList[1].Name = "This is not possible!";
}
}
希望这有帮助!
迎接
答案 3 :(得分:0)
特定缺乏协方差的另一种方法:
解决idictionary
上特定类型的有用协方差问题public static class DictionaryExtensions
{
public static IReadOnlyDictionary<TKey, IEnumerable<TValue>> ToReadOnlyDictionary<TKey, TValue>(
this IDictionary<TKey, List<TValue>> toWrap)
{
var intermediate = toWrap.ToDictionary(a => a.Key, a =>a.Value!=null? a.Value.ToArray().AsEnumerable():null);
var wrapper = new ReadOnlyDictionary<TKey, IEnumerable<TValue>>(intermediate);
return wrapper;
}
}
答案 4 :(得分:0)
根据您的使用情况,您可能会因暴露gcc
而逃脱。
Func<int,IReadOnly>