有效地从Dictionary<int,跳蚤中获取IReadOnlyDictionary<int,动物>>


public class Flea : Animals {...}
var fleas = new Dictionary<int, Flea>();
public IReadOnlyDictionary<string, Animal> Animals => fleas.ToDictionary(pair => pair.Key, pair => (Animal)pair.Value);

:有没有更有效的方法从fleas获取Animals

.NET 支持接口、委托、泛型类型和数组中的协方差。接口或类型必须指定其协变,但使用out关键字。

你可以写

IEnumerable<Animal> animals=new List<Flea>();

var dict=new Dictionary<int,Flea>{
[1]=new Flea()
};
IEnumerable<Animal> animals=dict.Values;

这是有效的,因为Dictionary.Values返回一个IEnumerable<Flea>并且 IEnumerable 是协变的 - 它的定义是IEnumerable<out T>

KeyValuePair虽然不是协变的,这意味着使用它的类(如IDictionary<TKey,TValue>IReadOnlyDictionary<TKey,TValue>也不是。这是故意的。

由于只需从该字典中读取,因此可以使用委托或在 C# 7 及更高版本中创建本地函数来创建访问器方法。可以将该函数传递给需要Func<TKey,TValue>的方法,并使用它来从字典中读取值。

如果你有一个需要基于密钥的访问的方法,假设:

void Process(Func<int,Animal> reader)
{
var value=reader(1);
}

在 C# 7 中,您可以编写:

var dict =...
Animal get(int key)=>dict[key];
Process(get);

通过使用变量捕获来访问字典,这有点作弊。

在 C# 7 之前,您将使用委托:

Func<int,Animal> get= key=>dict[key];
Process(get);

这可能看起来很奇怪,但这就是LINQ本身的工作方式,通过使用谓词和委托而不是接口和包装器。

.NET 框架不包含支持向上转换的字典包装器,但实现一个是微不足道的:

public class ReadOnlyDictionaryUpcast<TKey, TValueDerived, TValueBase>
: IReadOnlyDictionary<TKey, TValueBase> where TValueDerived : TValueBase
{
private readonly Dictionary<TKey, TValueDerived> _dictionary;
public ReadOnlyDictionaryUpcast(Dictionary<TKey, TValueDerived> dictionary)
{
_dictionary = dictionary;
}
public int Count => _dictionary.Count;
public TValueBase this[TKey key] => _dictionary[key];
public bool ContainsKey(TKey key) => _dictionary.ContainsKey(key);
public bool TryGetValue(TKey key, out TValueBase value)
{
bool result = _dictionary.TryGetValue(key, out TValueDerived valueDerived);
value = valueDerived;
return result;
}
public IEnumerator<KeyValuePair<TKey, TValueBase>> GetEnumerator() => _dictionary
.Select(e => new KeyValuePair<TKey, TValueBase>(e.Key, e.Value))
.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerable<TKey> Keys => _dictionary.Keys;
public IEnumerable<TValueBase> Values => 
(IEnumerable<TValueBase>)(IEnumerable<TValueDerived>)_dictionary.Values;
}

使用示例:

var animals = new ReadOnlyDictionaryUpcast<string, Flea, Animal>(fleas);

相关内容

  • 没有找到相关文章

最新更新