Компилятор С# выбирает неправильный метод расширения
Рассмотрим этот код:
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 имеет внутренний класс с методами расширения в глобальном пространстве имен (вот оно).
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
Это ошибка компилятора, недоступная функция не должна влиять на разрешение перегрузки.
Как общее обходное решение, используйте лямбды в качестве аргумента вместо групп методов, потому что разрешение перегрузки, похоже, отлично работает с ними. Не очевидно, что быстрее или эффективнее в вашем конкретном сценарии, при необходимости оптимизируйте его с помощью соответствующих показателей производительности.
В этом конкретном случае вы также можете использовать другие методы расширения, такие как Enumerable.Intersect()
если вы работаете с наборами и не интересуетесь дубликатами, Enumerable.Join()
или простой цикл.
Для получения дополнительной информации проверьте: