Перегрузка в универсальных классах

Несмотря на то что сигнатуры при объявлении должны быть уникальными, при замене аргументов типа могут создаваться идентичные сигнатуры. В таких случаях конечные правила разрешения перегрузки, описанные выше, позволят выбрать конкретный член.

В следующих примерах показываются допустимые и недопустимые в соответствии с этим правилом перегрузки:

interface I1<T> {...}

interface I2<T> {...}

class G1<U>
{
int F1(U u); // Overload resulotion for G<int>.F1
int F1(int i); // will pick non-generic

void F2(I1<U> a); // Valid overload
void F2(I2<U> a);
}

class G2<U,V>
{
void F3(U u, V v); // Valid, but overload resolution for
void F3(V v, U u); // G2<int,int>.F3 will fail

void F4(U u, I1<V> v); // Valid, but overload resolution for
void F4(I1<V> v, U u); // G2<I1<int>,int>.F4 will fail

void F5(U u1, I1<V> v2); // Valid overload
void F5(V v1, U u2);

void F6(ref U u); // valid overload
void F6(out V v);
}

Проверка динамического разрешения перегрузки во время компиляции

Для основных динамически связанных операций набор возможных кандидатов для разрешения во время компиляции неизвестен. В некоторых случаях, однако, набор кандидатов известен во время компиляции:

· Вызовы статических методов с динамическими аргументами

· Вызовы методов экземпляра, в случаях, когда получатель не является динамическим выражением

· Вызовы индексатора, в случаях, когда получатель не является динамическим выражением

· Вызовы конструктора с динамическими аргументами

В этих случаях для каждого кандидата выполняется ограниченная проверка времени компиляции, выявляющая потенциальную применимость во время выполнения. Эта проверка состоит из следующих этапов:

· Частичный вывод типа: Любой аргумент типа, не зависящий напрямую или косвенно от аргумента типа dynamic, выводится с использованием правил §7.5.2. Остальные аргументы типа неизвестны.

· Частичная проверка применимости: Проверяется применимость в соответствии с §7.5.3.1, но параметры, тип которых неизвестен, пропускаются.

Если кандидатов, прошедших эту проверку, нет, происходит ошибка времени компиляции.

Вызов функции-члена

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

В целях описания процесса вызова функции-члены разделены на две категории.

· Статические функции-члены. Это конструкторы экземпляров, статические методы, методы доступа к статическим свойствам и пользовательские операторы. Статические функции-члены всегда являются невиртуальными.

· Функции-члены экземпляра. Это методы экземпляра, методы доступа к свойствам и индексаторам. Функции-члены экземпляра могут быть либо виртуальными, либо невиртуальными и всегда вызываются для конкретного экземпляра. Экземпляр вычисляется по выражению экземпляра и оказывается доступен внутри функции-члена с помощью оператора this (§7.6.7).

Обработка вызова функции-члена во время выполнения состоит из следующих этапов, где M —это функция-член, а E — это выражение экземпляра (когда M является членом экземпляра).

· Если M является статической функцией-членом

o Список аргументов вычисляется, как описано в разделе §7.5.1.

o Вызывается M.

· Если M является функцией-членом экземпляра, объявленной в типе значения:

o Вычисляется E. Если при этом вычислении возникает исключение, дальнейшие этапы не выполняются.

o Если E не является переменной, то создается временная локальная переменная типа E и этой переменной присваивается значение E. После этого E становится ссылкой на эту временную локальную переменную. Временная переменная доступна с помощью оператора this в M, но не другим способом. Таким образом, вызывающий может наблюдать изменения, проводимые в M для this, только когда E является настоящей переменной.

o Список аргументов вычисляется, как описано в разделе §7.5.1.

o Вызывается M. Переменная, на которую ссылается E, становится переменной, на которую ссылается this.

· Если M является функцией-членом экземпляра, объявленной в ссылочном типе:

o Вычисляется E. Если при этом вычислении возникает исключение, дальнейшие этапы не выполняются.

o Список аргументов вычисляется, как описано в разделе §7.5.1.

o Если E имеет тип значения, выполняется преобразование упаковки (§4.3.1) для преобразования E в тип object. На следующих этапах считается, что E имеет тип object. В данном случае M может быть только членом System.Object.

o Выполняется проверка допустимости значения E. Если E имеет значение null, вызывается исключение System.NullReferenceException и дальнейшие действия не выполняются.

o Определяется реализация вызываемой функции-члена.

· Если типом E во время компиляции является интерфейс, то вызываемой функцией-членом является реализация M, предоставленная типом времени выполнения экземпляра, на который ссылается E. Эта функция-член определяется применением правил сопоставления интерфейса (§13.4.4), чтобы определить реализацию M, предоставленную типом времени выполнения экземпляра, на который ссылается E.

· Иначе, если M является виртуальной функцией-членом, вызываемая функция-член является реализацией M, предоставленной типом времени выполнения экземпляра, на который ссылается E. Эта функция-член определяется применением правил определения самой производной реализации (§10.6.3) M в соответствии с типом времени выполнения экземпляра, на который ссылается E.

· Иначе M является невиртуальной функцией-членом, и вызываемой функцией-членом является сама M.

o Вызывается реализация функции-члена, определенная на этапе выше. Объект, на который ссылается E, становится объектом, на который ссылается this.

Наши рекомендации