Подтвердить что ты не робот

Общие методы и перегрузка метода

Перегрузка метода позволяет нам определять многие методы с тем же именем, но с другим набором параметров (с тем же именем, но с другой подписью).

Перегружены ли эти два метода?

class A
{
    public static void MyMethod<T>(T myVal) { }
    public static void MyMethod(int myVal) { }
}

EDIT:

Не следует выводить A<int>.MyMethod(myInt); ошибку, так как построенный тип A<int> имеет два метода с одинаковым именем и одной и той же сигнатурой?

4b9b3361

Ответ 1

Перегружены ли эти два метода?

Да.

Не следует вызывать A<int>.MyMethod(myInt); ошибку, так как построенный тип A<int> имеет два метода с одинаковой сигнатурой?

Вопрос не имеет смысла; A не является общим типом, как вы его объявили. Возможно, вы хотели спросить:

Если оператор A.MyMethod(myInt); заставляет компилятор сообщать об ошибке, так как существуют два двусмысленных метода кандидата?

Нет. Как говорили другие, в этом случае перегрузочное разрешение предпочитает не-общую версию. Подробнее см. Ниже.

Или, возможно, вы хотели спросить:

Если объявление типа A является незаконным в первую очередь, поскольку в некотором смысле оно имеет два метода с одинаковой сигнатурой, MyMethod и MyMethod<int>?

Нет. Тип A является совершенно законным. Общая арность является частью подписи. Таким образом, нет двух методов с одной и той же сигнатурой, потому что первый имеет ноль нулевой, но второй имеет общую arity.

Или, возможно, вы хотели спросить:

class G<T> 
{
    public static void M(T t) {}
    public static void M(int t) {}
}

Общий тип G<T> можно построить таким образом, чтобы он имел два метода с одной и той же сигнатурой. Разрешено ли объявлять такой тип?

Да, законно объявлять такой тип. Обычно это плохая идея, но она легальна.

Затем вы можете ответить:

Но моя копия спецификации С# 2.0, опубликованная Addison-Wesley, указана на стр. 479 "Два члена функции, объявленные с одинаковыми именами... должны иметь типы параметров, так что никакой замкнутый сконфигурированный тип может иметь два члена с имя и подпись". Что с этим?

Когда С# 2.0 был первоначально разработан, это был план. Однако тогда дизайнеры поняли, что эта желательная картина будет сделана незаконной:

class C<T> 
{
    public C(T t) { ... } // Create a C<T> from a given T
    public C(Stream s) { ... } // Deserialize a C<T> from disk
}

И теперь мы говорим извините, что вы можете сказать C<Stream>, в результате чего два конструктора объединяются, весь класс является незаконным. Это было бы неудачно. Очевидно, маловероятно, что кто-нибудь когда-нибудь создаст эту вещь с Stream как параметр типа!

К сожалению, спецификация нажимала до того, как текст был обновлен до окончательной версии. Правило на стр. 479 не является тем, что мы реализовали.

Продолжая задавать еще несколько вопросов от вашего имени:

Итак, что произойдет, если вы вызываете G<int>.M(123) или, в исходном примере, если вы вызываете A.MyMethod(123)?

Когда разрешение перегрузки сталкивается с двумя методами, которые имеют идентичные подписи из-за общей конструкции, то родовая конструкция считается "менее конкретной", чем "естественная". Менее конкретный метод теряет более конкретный метод.

Так почему же это плохая идея, если работает разрешение перегрузки?

Ситуация с A.MyMethod не так уж плоха; обычно довольно легко однозначно определить, какой метод предназначен. Но ситуация с G<int>.M(123) намного хуже. Правила CLR создают такую ​​ситуацию "поведение, определяемое реализацией", и поэтому может произойти любая старая вещь. Технически, CLR может отказаться проверять программу, которая строит тип G<int>. Или это может упасть. На самом деле это не так; он делает все возможное с плохой ситуацией.

Есть ли примеры такого типа построения, вызывающие по-настоящему поведение, определяемое реализацией?

Да. Подробнее см. В этих статьях:

http://blogs.msdn.com/b/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx

http://blogs.msdn.com/b/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx

Ответ 2

Да. MyMethod(int myVal) будет вызываться, когда типом параметра является int, общая перегрузка будет вызываться для всех других аргументов параметра, даже если аргумент параметра неявно конвертируется в (или является производным классом) жестко закодированного типа, Разрешение перегрузки будет лучше всего подходит, и общая перегрузка будет разрешена для точного соответствия во время компиляции.

Примечание. Вы можете явно вызвать общую перегрузку и использовать int, указав параметр типа в вызове метода, как указывает в своем ответе Стивен Судит.

short s = 1;
int i = s;
MyMethod(s); // Generic
MyMethod(i); // int
MyMethod((int)s); // int
MyMethod(1); // int
MyMethod<int>(1); // Generic**
MyMethod(1.0); // Generic
// etc.

Ответ 3

Да, они есть. Они позволят использовать код как таковой:

A.MyMethod("a string"); // calls the generic version
A.MyMethod(42);  // calls the int version

Ответ 4

Да, они перегружены. Предполагается, что компилятор предпочитает явные сигнатуры методов против общих методов, если они доступны. Остерегайтесь, однако, что, если вы можете избежать такой перегрузки, вы, вероятно, должны. Были сообщения об ошибках в отношении такого рода перегрузок и неожиданного поведения.

https://connect.microsoft.com/VisualStudio/feedback/details/522202/c-3-0-generic-overload-call-resolution-from-within-generic-function

Ответ 5

Да. Они имеют одно и то же имя "MyMethod", но разные подписи. Однако спецификация С# специально описывает это, говоря, что компилятор предпочтет не-общую версию в общей версии, если оба варианта.

Ответ 6

Да. В верхней части головы, если вы вызываете A.MyMethod(1);, он всегда будет запускать второй метод. Вам нужно будет вызвать A.MyMethod<int>(1);, чтобы заставить его запустить первый.