Ответ 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