当方法具有IDictionary和IDictionary的重载时的模糊调用<tkey,tvalue =“”> </tkey,>

时间:2013-04-24 16:48:50

标签: c# .net compiler-errors overloading ambiguous

当一个方法有两个重载时,一个接受IDictionary而另一个接受IDictionary<TKey, TValue>,将new Dictionary<string, int>()传递给它会被认为是不明确的。但是,如果将两个重载更改为接受IEnumerableIEnumerable<KeyValuePair<TKey, TValue>>,则呼叫将不再具有模糊性。

由于Dictionary<TKey, TValue>实现了上述所有接口(确切地说,IDictionary<TKey, TValue>ICollection<KeyValuePair<TKey, TValue>>IDictionaryICollectionIReadOnlyDictionary<TKey, TValue>, .NET 4.5中的IReadOnlyCollection<KeyValuePair<TKey, TValue>>IEnumerable<KeyValuePair<TKey, TValue>>IEnumerableISerializableIDeserializationCallback;由于IDictionary继承自IEnumerableIDictionary<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:如果一个类同时实现这两个参数,如何接受泛型和非泛型参数而不引起歧义?

2 个答案:

答案 0 :(得分:6)

C#将调用最具体的过载。将IEnumerable<T>标识为IEnumerableIEnumerable<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>是不可能的,因为这两个接口不相关。

如果您有接受IDictionaryIDictionary<TKey, TValue>的重载,则必须将您的参数转换为您想要的类型:

FooDic((IDictionary)value);

FooDic((IDictionary<TKey, TValue>)value);