#c# #generics
Вопрос:
Я пытаюсь добавить этот метод расширения:
public static bool Contains<T>(this IEnumerable<T> source, Nullable<T> value)
where T : struct
{
if (value == null)
{
return false;
}
return source.Contains(value.Value);
}
Однако он зацикливается и вызывает переполнение стека, потому что последняя строка приводит к обратному вызову этого метода расширения, а не System.Linq.Contains<T>(this IEnumerable<T> source, T value)
метода, который, на мой взгляд, лучше подходит, поскольку аргумент Contains
больше не является Nullable<T>
прямым, а просто прямым T
.
Я могу обойти это, переименовав свой метод расширения, но я хотел бы понять, что здесь происходит.
Комментарии:
1. @Charlieface: Я бы не решился ссылаться на VB.NET документы для вопроса на C#. В VB.NET правила, возможно, были настроены в соответствии с правилами C# (я не знаю, я не проверял), но правила разрешения перегрузки в любом случае не являются общими для языков .NET как таковых, поскольку это (в основном) работа компилятора, а не среды выполнения. Безусловно, оба VB.NET а спецификации C# для разрешения перегрузки достаточно сложны, поэтому с первого взгляда трудно сказать, одинаковы ли они во всех случаях, даже если они подходят для данного конкретного случая.
2. Извините, что это здесь docs.microsoft.com/en-us/dotnet/csharp/language-reference/… @JeroenMostert Вы совершенно правы, вот что происходит, когда вы прогугливаете очевидное разрешение перегрузки C# , выбираете первый вариант и не смотрите слишком внимательно.
Ответ №1:
Чтобы ответить на этот вопрос, нам нужно посмотреть, как компилятор разрешает методы расширения.
Глядя на спецификацию C# в MSDN (вы также можете увидеть это в ECMA-334 12.7.6.3):
если обычная обработка вызова не находит применимых методов, предпринимается попытка обработать конструкцию как вызов метода расширения.
….Цель состоит в том
C
, чтобы найти лучшее имя типа, чтобы можно было выполнить соответствующий вызов статического метода:
….
ПоискC
продолжается следующим образом:
- Начиная с объявления ближайшего окружающего пространства имен[мой жирный шрифт], продолжая каждым объявлением окружающего пространства имен и заканчивая содержащим блоком компиляции, предпринимаются последовательные попытки найти подходящий набор методов расширения:
- Если данное пространство имен или модуль компиляции напрямую содержит объявления неродовых типов
Ci
с подходящими методами расширенияMj
, то набор этих методов расширения является набором кандидатов.- Если типы
Ci
, импортированные с помощью using_static_declarations и непосредственно объявленные в пространствах имен, импортированных с помощью using_namespace_directives в данном пространстве имен или блоке компиляции, напрямую содержат подходящие методы расширенияMj
, то набор этих методов расширения является набором кандидатов.
…
разрешение перегрузки применяется к набору кандидатов, как описано в (Разрешение перегрузки).
C
это тип, в котором лучший метод объявляется как метод расширения. [мой жирный шрифт]
Другими словами, рассматривается только один класс расширения, если в нем найден метод расширения, все остальные классы расширения игнорируются.
Подводя итог:
Предыдущие правила означают, что методы экземпляра имеют приоритет над расширением методов, что методы расширения существующих во внутреннем пространстве имен заявления имеют приоритет над расширением методов, доступных в космическом пространстве имен деклараций [мой смелый], и что методы расширения, объявленные непосредственно в пространстве имен имеют приоритет над расширением методов импортировать в том же пространстве имен с помощью директивы пространства имен.