C#编译器选择错误的扩展方法

时间:2018-03-29 10:53:15

标签: c# .net

考虑以下代码:

using System.Linq;

namespace ExtensionMethodIssue
{
    static class Program
    {
        static void Main(string[] args)
        {
            var a = new[] { 1 };
            var b = new[] { 1, 2 }.Where(a.Contains).ToList();
            var c = new[] { 1, 2 }.Where(i => a.Contains(i)).ToList();
        }
    }
}

代码编译成功。 然后我添加nuget包“itext7 7.0.4”,现在编译失败的原因是:

//Error CS0122: 'KernelExtensions.Contains<TKey, TValue>(IDictionary<TKey, TValue>, TKey)' is inaccessible due to its protection level
var b = new[] { 1, 2, 3 }.Where(a.Contains).ToList();

// This is still ok.
var c = new[] { 1, 2, 3 }.Where(i => a.Contains(i)).ToList();

原因是itext7库在全局命名空间(here it is)中有一个带有扩展方法的内部类。

internal static class KernelExtensions {
    public static bool Contains<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key) {
        return dictionary.ContainsKey(key);
}
}

由于某种原因,编译器选择了一个不可访问的扩展方法,该方法使用来自全局命名空间的不兼容签名,而不是来自LINQ命名空间的兼容签名的可访问扩展方法。

问题是:这种行为是否符合语言规范,或者是编译器中的错误?为什么它仅在“方法组”的情况下失败并仍然与i => a.Contains(i)一起使用?

1 个答案:

答案 0 :(得分:3)

这是一个编译器错误,一个不可访问的函数不应该影响重载解析。

作为一般的解决方法,使用lambdas作为参数而不是方法组,因为重载解析似乎可以正常使用它们。在您的特定情况下,哪个更快/更有效,使用相关性能指标进行微观优化并不明显。

在这种特殊情况下,如果您正在使用集合,也可以使用其他扩展方法,例如Enumerable.Intersect(),并且不关心重复,Enumerable.Join()或简单循环。

有关详细信息,请查看: