当一个方法有两个重载时,一个接受IDictionary
而另一个接受IDictionary<TKey, TValue>
,将new Dictionary<string, int>()
传递给它会被认为是不明确的。但是,如果将两个重载更改为接受IEnumerable
和IEnumerable<KeyValuePair<TKey, TValue>>
,则呼叫将不再具有模糊性。
由于Dictionary<TKey, TValue>
实现了上述所有接口(确切地说,IDictionary<TKey, TValue>
,ICollection<KeyValuePair<TKey, TValue>>
,IDictionary
,ICollection
,IReadOnlyDictionary<TKey, TValue>
, .NET 4.5中的IReadOnlyCollection<KeyValuePair<TKey, TValue>>
,IEnumerable<KeyValuePair<TKey, TValue>>
,IEnumerable
,ISerializable
,IDeserializationCallback
;由于IDictionary
继承自IEnumerable
且IDictionary<TKey, TValue>
继承自IEnumerable<KeyValuePair<TKey, TValue>>
,我无法理解为何会发生这种情况。
示例控制台应用程序:
using System;
using System.Collections;
using System.Collections.Generic;
namespace AmbigousCall
{
internal class Program
{
static void Main (string[] args)
{
var dic = new Dictionary<string, int>();
FooDic(dic); // Error: The call is ambiguous
FooEnum(dic); // OK: The generic method is called
Console.ReadKey();
}
static void FooDic (IDictionary dic) {}
static void FooDic<TKey, TValue> (IDictionary<TKey, TValue> dic) {}
static void FooEnum (IEnumerable dic) {}
static void FooEnum<TKey, TValue> (IEnumerable<KeyValuePair<TKey, TValue>> dic) {}
}
}
我得到的错误是:以下方法或属性之间的调用不明确:'AmbigousCall.Program.FooDic(System.Collections.IDictionary)'和'AmbigousCall.Program.FooDic(System.Collections.Generic) .IDictionary)'
问题1:为什么会发生?
问题2:如果一个类同时实现这两个参数,如何接受泛型和非泛型参数而不引起歧义?
答案 0 :(得分:6)
C#将调用最具体的过载。将IEnumerable<T>
标识为IEnumerable
比IEnumerable<T>
更具体,因为IEnumerable
扩展IDictionary<T, U>
。但是,IDictionary
不扩展Dictionary<T, U>
,因此即使FooDic((IDictionary)dic); // not ambiguous
FooDic((IDictionary<string, int>)dic); // not ambiguous
同时实现这两者,编译器也无法识别哪个更具体。对于编译器,这些也可能是完全不相关的接口。
您必须使用显式强制转换为编译器提供提示:
{{1}}
答案 1 :(得分:4)
区别在于IEnumerable<T>
继承了IEnumerable
,而IDictionary<TKey, TValue>
没有继承IDictionary
。
因此,在接受IEnumerable<T>
和IEnumerable
的重载之间进行解析只需确定参数是否与更具体或更一般的版本匹配,而在IDictionary
之间解析并且IDictionary<TKey, TValue>
是不可能的,因为这两个接口不相关。
如果您有接受IDictionary
和IDictionary<TKey, TValue>
的重载,则必须将您的参数转换为您想要的类型:
FooDic((IDictionary)value);
或
FooDic((IDictionary<TKey, TValue>)value);