Ответ 1
Ваш вопрос был горячо обсужден, когда разрабатывались С# 2.0 и система типового типа в CLR. Так горячо, на самом деле, что "связанная" спецификация С# 2.0, опубликованная A-W, фактически имеет неправильное правило в ней! Существует четыре возможности:
1) Сделать незаконным объявление общего класса, который может быть POSSIBLY неоднозначным в рамках НЕКОТОРЫХ конструкций. (Это неверно указывает связанная спецификация.) Таким образом, ваше объявление Foo<T>
было бы незаконным.
2) Сделать незаконным создание универсального класса способом, который создает неоднозначность. объявление Foo<T>
было бы законным, построение Foo<double>
было бы законным, но построение Foo<int>
было бы незаконным.
3) Сделайте все законным и используйте трюки с разрешением перегрузки, чтобы выяснить, лучше ли общая или неродственная версия. (Это то, что на самом деле делает С#.)
4) Сделайте что-то еще, о чем я не думал.
Правило № 1 - плохая идея, потому что это делает некоторые очень распространенные и безопасные сценарии невозможными. Рассмотрим, например:
class C<T>
{
public C(T t) { ... } // construct a C that wraps a T
public C(Stream state) { ... } // construct a C based on some serialized state from disk
}
Вы хотите, чтобы это было незаконным только потому, что C<Stream>
неоднозначно? Тьфу. Правило № 1 - это плохая идея, поэтому мы ее отказали.
К сожалению, это не так просто. IIRC правила CLI говорят, что реализации разрешено отклонять как незаконные конструкции, которые фактически вызывают неоднозначность сигнатур. То есть правила CLI являются чем-то вроде правила №2, тогда как С# фактически реализует правило № 3. Это означает, что теоретически могут быть законные С# -программы, которые переводят на незаконный код, что очень печально.
Еще несколько мыслей о том, как эти разногласия делают наши жизни несчастными, вот несколько статей, которые я написал на эту тему:
http://blogs.msdn.com/ericlippert/archive/2006/04/05/569085.aspx
http://blogs.msdn.com/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx