Как система обработки перегрузки метода решает, какой метод вызывать при передаче пустого значения?

Например, у вас есть тип типа:

public class EffectOptions { public EffectOptions ( params object [ ] options ) {} public EffectOptions ( IEnumerable options ) {} public EffectOptions ( string name ) {} public EffectOptions ( object owner ) {} public EffectOptions ( int count ) {} public EffectOptions ( Point point ) {} } 

Здесь я просто приведу пример с использованием конструкторов, но результат будет таким же, если бы они были неконструкторскими методами для самого типа, так?

Поэтому, когда вы это делаете:

 EffectOptions options = new EffectOptions (null); 

какой конструктор будет называться, и почему?

Я мог проверить это сам, но я хочу понять, как работает система разрешения перегрузки (не уверен, что это то, что она называется).

    Точные правила см. В спецификации разрешения перегрузки . Но вкратце, все идет так.

    Сначала создайте список всех доступных конструкторов.

     public EffectOptions ( params object [ ] options ) public EffectOptions ( IEnumerable options ) public EffectOptions ( string name ) public EffectOptions ( object owner ) public EffectOptions ( int count ) public EffectOptions ( Point point ) 

    Затем устраните все неприменимые конструкторы. Применимый конструктор – это тот, где каждый формальный параметр имеет соответствующий аргумент, а аргумент неявно конвертируется в формальный тип параметра. Предполагая, что Точка является типом значения, мы исключаем версии «int» и «Point». Это оставляет

     public EffectOptions ( params object[] options ) public EffectOptions ( IEnumerable options ) public EffectOptions ( string name ) public EffectOptions ( object owner ) 

    Теперь мы должны рассмотреть, применим ли тот, у кого есть «параметры» в его расширенной или нерасширенной форме. В этом случае это применимо в обеих формах. Когда это произойдет, мы отбрасываем развернутую форму. Так что листья

     public EffectOptions ( object[] options ) public EffectOptions ( IEnumerable options ) public EffectOptions ( string name ) public EffectOptions ( object owner ) 

    Теперь мы должны определить лучших кандидатов. Правила бестселлера сложны, но короткая версия – более конкретная, чем менее конкретная . Жираф более специфичен, чем млекопитающее, млекопитающее более специфично, чем животное, животное более конкретное, чем объект.

    «Объектная» версия менее конкретна, чем все из них, поэтому ее можно устранить. Версия IEnumerable менее специфична, чем версия object[] (вы видите, почему?), Поэтому ее можно также устранить. Это оставляет

     public EffectOptions ( object[] options ) public EffectOptions ( string name ) 

    И теперь мы застряли. объект [] не более или менее специфичен, чем строка. Поэтому это дает ошибку неоднозначности.

    Это всего лишь краткий очерк; реальный алгоритм tiebreaking намного сложнее. Но это основы.

    В этом случае компилятор C # не будет выбирать какой-либо конструктор и вместо этого будет ошибкой. Значение null является допустимым для нескольких доступных конструкторов, и для его выбора недостаточно логики разлома, поэтому она вызывает ошибку.

    Логика разрешения перегрузки компилятора C # представляет собой сложный процесс, но короткий (и по сути неполный) обзор того, как он работает, выглядит следующим образом

    • Соберите всех членов с данным именем
    • Отфильтруйте элементы с теми, у кого есть списки параметров, которые совместимы с предоставленными аргументами и с соответствующей доступностью
    • Если остальные члены имеют более одного элемента, используйте логику привязки для выбора лучших из них

    Полная информация приведена в разделе 7.4 спецификации языка C #. И я уверен, что Эрик скоро отправится, чтобы дать гораздо более точное описание 🙂

    Давайте будем гением компьютера.