考虑以下代码:
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)
一起使用?
答案 0 :(得分:3)
这是一个编译器错误,一个不可访问的函数不应该影响重载解析。
作为一般的解决方法,使用lambdas作为参数而不是方法组,因为重载解析似乎可以正常使用它们。在您的特定情况下,哪个更快/更有效,使用相关性能指标进行微观优化并不明显。
在这种特殊情况下,如果您正在使用集合,也可以使用其他扩展方法,例如Enumerable.Intersect()
,并且不关心重复,Enumerable.Join()
或简单循环。
有关详细信息,请查看: