8

当一个方法有两个重载,一个接受IDictionary和另一个接受IDictionary<TKey, TValue>时,传递new Dictionary<string, int>()给它被认为是模棱两可的。但是,如果将两个重载更改为 acceptIEnumerableIEnumerable<KeyValuePair<TKey, TValue>>,则调用不再模棱两可。

AsDictionary<TKey, TValue>实现上述所有接口(准确地说,.NET 4.5 中的 ,IDictionary<TKey, TValue>​​ , ICollection<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IReadOnlyDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, );继承自和继承自,我不明白为什么会发生这种情况。ISerializableIDeserializationCallbackIDictionaryIEnumerableIDictionary<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:如果一个类同时实现了泛型和非泛型参数,那么如何同时接受泛型和非泛型参数而不引起歧义?

4

2 回答 2

9

C# 将调用最具体的可用重载。IEnumerable<T>识别比IEnumerable因为IEnumerable<T>extends更具体没有问题IEnumerable。但是,IDictionary<T, U>不扩展,因此即使实现了两者,编译器也无法识别哪个更具体。对于编译器来说,这些也可能是完全不相关的接口。IDictionaryDictionary<T, U>

您必须使用显式强制转换给编译器一个提示:

FooDic((IDictionary)dic); // not ambiguous
FooDic((IDictionary<string, int>)dic); // not ambiguous
于 2013-04-24T16:53:59.080 回答
4

区别在于IEnumerable<T>继承IEnumerable,而IDictionary<TKey, TValue>没有继承IDictionary

因此,在接受IEnumerable<T>and的重载之间解析IEnumerable是一个简单的问题,即确定参数是否匹配更具体或更通用的版本,而在IDictionaryand之间解析IDictionary<TKey, TValue>是不可能的,因为这两个接口不相关。

如果您有接受IDictionaryand的重载,IDictionary<TKey, TValue>则必须将参数转换为所需的类型:

FooDic((IDictionary)value);

或者

FooDic((IDictionary<TKey, TValue>)value);
于 2013-04-24T16:55:06.457 回答