简体   繁体   中英

Compiler cannot infer type from wrapped generic IEnumerable

I am trying to write a generic extension method for a dictionary of type Dictionary<TKey, IEnumerable<TValue>> that should return the instance of the IEnumerable<TValue> for a given key and if there is no entry yet for that key create a new instance of IEnumerable<TValue> and add it for that key.

public static TEnumerable GetAndEnsureEnumerableForKey<TKey, TValue, TEnumerable>(
  this Dictionary<TKey, TEnumerable> dictionary, TKey key)
    where TEnumerable : IEnumerable<TValue> 
{
  TEnumerable enumerableForKey;
  if (!dictionary.TryGetValue(key, out enumerableForKey)) 
  {
    Type enumerableType = typeof(TEnumerable);
    enumerableForKey = (TEnumerable)Activator.CreateInstance(enumerableType);
    dictionary.Add(key, enumerableForKey);
  }

  return enumerableForKey;
}

The method itself works fine, but i have a problem with the invocation of that method. Given a Dictionary<int, List<int>> intListDictionary i would expect the call intListDictionary.GetAndEnsureEnumerableForKey(sampleInt); to work just fine. However the compiler complains that it is not able to infer the type TValue from the method call and i would have to call intListDictionary.GetAndEnsureEnumerableForKey<int, int, List<int>>(sampleInt); which kind of defeats the purpose of generics for that case.

How does it come that the compiler cannot infer the type TValue when TEnumerable is constraint to be an IEnumerable<TValue> and the concrete dictionary i am calling from should know the type?

Type inferences are only made based on type arguments, not type constraints, as explained in this answer .

To achieve what you want, you can change the type constraint for TEnumerable to the non-generic IEnumerable interface:

public static TEnumerable GetAndEnsureEnumerableForKey<TKey, TEnumerable>(
    this Dictionary<TKey, TEnumerable> dictionary,
    TKey key)
    where TEnumerable : IEnumerable
{
    TEnumerable enumerableForKey;
    if (!dictionary.TryGetValue(key, out enumerableForKey))
    {
        Type enumerableType = typeof(TEnumerable);
        enumerableForKey = (TEnumerable)Activator.CreateInstance(enumerableType);
        dictionary.Add(key, enumerableForKey);
    }

    return enumerableForKey;
}

You need to add the System.Collections to make the IEnumerable interface accessible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM