public class Flea : Animals {...}
var fleas = new Dictionary<int, Flea>();
public IReadOnlyDictionary<string, Animal> Animals => fleas.ToDictionary(pair => pair.Key, pair => (Animal)pair.Value);
Q Is there a more efficient way to obtain Animals from fleas?
.NET supports covariance in interfaces, delegates, generic types and arrays. The interface or type has to specify it's covariant though with the out keyword.
You can write
IEnumerable<Animal> animals=new List<Flea>();
or
var dict=new Dictionary<int,Flea>{
[1]=new Flea()
};
IEnumerable<Animal> animals=dict.Values;
This works because Dictionary.Values returns an IEnumerable<Flea> and IEnumerable is covariant - its definition is IEnumerable<out T>.
KeyValuePair though isn't covariant which means that the classes that use it like IDictionary<TKey,TValue> and IReadOnlyDictionary<TKey,TValue> aren't either. This was intentional.
Since you only need to read from that dictionary, you can create an accessor method using a delegate or, in C# 7 and later, a local function. You can pass that function to methods that expect a Func<TKey,TValue> and use it to read values from the dictionary.
If you have a method that needs key-based access, let's say :
void Process(Func<int,Animal> reader)
{
var value=reader(1);
}
In C# 7 you can write :
var dict =...
Animal get(int key)=>dict[key];
Process(get);
This cheats a bit, by using variable capture to access the dictionary.
Before C# 7 you'd use a delegate :
Func<int,Animal> get= key=>dict[key];
Process(get);
This may seem strange, but that's how LINQ itself works, by using predicates and delegates instead of interfaces and wrappers.
The .NET framework does not contain a dictionary wrapper that supports upcasting, but implementing one is trivial:
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;
}
Usage example:
var animals = new ReadOnlyDictionaryUpcast<string, Flea, Animal>(fleas);
来源:https://stackoverflow.com/questions/56593508/efficiently-obtain-ireadonlydictionaryint-animals-from-dictionaryint-fleas