2009-08-09 2 views
2

Интересно, почему команда C# решила не поддерживать совместную/контравариантность для не-дженериков, учитывая, что они могут быть столь же безопасными. Вопрос довольно субъективен, так как я не ожидаю ответа члена команды, но у кого-то может быть понимание I (и Барбары Лисков).Поддержка Co-/Contravariance для нестандартных типов?

Давайте посмотрим на этот образец интерфейса:

public interface ITest 
{ 
    object Property 
    { 
     get; 
    } 
} 

Следующая реализация потерпит неудачу, хотя полностью безопасным (мы всегда могли вернуться более конкретный тип, не нарушая интерфейс - не в C#, но, по крайней мере, в теории).

public class Test : ITest 
{ 
    public string Property 
    { 
     get; 
    } 
} 

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

+0

Естественно, эта реализация также потерпит неудачу, потому что get не имеет тела, но для этого простого примера, пожалуйста, проигнорируйте этот факт ;-) –

+1

Dup: http://stackoverflow.com/questions/837134/why-does-c-clr -not-support-method-override-co-contra-variance – thecoop

+0

thecoop, я узнал сам, поэтому я дал свой голос за закрытие этого вопроса. –

ответ

2

CLR не поддерживает ковариантные типы возвращаемых данных, в то время как он поддерживает общую дисперсию делегата/интерфейса от .NET 2.0 и далее.

Другими словами, дело не в команде C#, а в команде CLR.

Относительно того, почему CLR не поддерживает нормальную дисперсию - я не уверен, кроме добавления сложности, предположительно без необходимого количества предполагаемой выгоды.

EDIT: Для борьбы с точкой относительно возврата типа ковариации, из раздела 8.10.4 из CLI спецификации, говорить о «виртуальных таблицах слотов»:

Для каждого нового члена, который помечен «ожидать существующий слот ", посмотрите, есть ли точное соответствие по типу (то есть поле или метод ), имя и подпись существует и использовать этот слот, если он найден, в противном случае выделите новый слот.

Из раздела II, раздел 9.9:

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

Нет указаний, что сравнение проводится таким образом, чтобы это допускало отклонение.

Если вы считаете, что CLR делает, допускайте отклонение, я думаю, что, учитывая приведенные выше доказательства, вам нужно доказать это с помощью соответствующего IL.

EDIT: У меня только пробовал в IL, и он не работает.Компиляция этот код:

using System; 

public class Base 
{ 
    public virtual object Foo() 
    { 
     Console.WriteLine("Base.Foo"); 
     return null; 
    } 
} 

public class Derived : Base 
{ 
    public override object Foo() 
    { 
     Console.WriteLine("Derived.Foo"); 
     return null; 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     Base b = new Derived(); 
     b.Foo(); 
    } 
} 

запустить его с выходом:

Derived.Foo 

Разобрать его:

ildasm Test.exe /out:Test.il 

Редактировать Derived.Foo иметь тип возвращаемого значения "строка" вместо "объекта" :

.method public hidebysig virtual instance string Foo() cil managed 

R Ебилд:

ilasm /OUTPUT:Test.exe Test.il 

Rerun это, с выходом:

Base.Foo 

Другими словами, Derived.Foo больше не отменяет Base.Foo насколько CLR обеспокоен.

+0

«Подпись метода определяет соглашение о вызове, тип параметров для метода и тип возврата метода "(из ECMA-335, 8.11.1). Поскольку CLR представляет собой реализацию CLI, не будет ли она поддерживать перегрузку типа возвращаемого типа и, таким образом, позволяет отклонять? –

+0

Нет, поскольку поддержка возвращаемого типа перегрузки * не является той же вещью, что и поддерживающая дисперсия. Я рассмотрю соответствующий бит на * overriding *, который является важной частью. –

+0

Это можно было бы обработать в компиляторе C#, добавив дополнительные метаданные в сборку и вставляя приведения в нужные места (например, как java имеет дело с дроидами - стирание + литье) – thecoop

1
  1. Возвращенное значение метода всегда «вне», они всегда находятся на правой стороне выражения присваивания.
  2. Формат сборки CLR имеет метаданные, которые присваивают методы экземпляра методам интерфейса, но этот вывод метода зависит только от входных параметров, им может потребоваться создать новый формат для поддержки, а не только в том, что он также становится неоднозначным.
  3. Новый алгоритм сопоставления методов между методом экземпляра и сигнатурой интерфейса может быть сложным и интенсивным. И я верю, что подписи методов интерфейса решаются во время компиляции. Потому что во время работы это может быть слишком дорого.
  4. Метод вывода/разрешения может быть проблемой, как описано ниже.

Рассмотрит следующий образец с разрешенным динамическим методом только с типами различными обратными (что совершенно неправильно)

public class Test{ 
    public int DoMethod(){ return 2; } 
    public string DoMethod() { return "Name"; } 
} 
Test t; 
int n = t.DoMethod(); // 1st method 
string txt = t.DoMethod(); // 2nd method 
object x = t.DoMethod(); // DOOMED ... which one?? 
+0

Эта проблема существует уже сегодня, если у вас есть класс, который реализует два интерфейса и передает экземпляр методу, который имеет перегрузки для обоих интерфейсов. –

+0

Как я прокомментировал Jon Skeet, в CTS подпись метода включает в себя тип возврата. –

1

Среда CLR не поддерживает дисперсию на метод переопределяет, но есть обходной путь для реализации интерфейса :

public class Test : ITest 
{ 
    public string Property 
    { 
     get; 
    } 

    object ITest.Property 
    { 
     get 
     { 
      return Property; 
     } 
    } 
} 

Это позволит достичь тот же эффект, что и ковариантного переопределение, но может быть использовано только для интерфейсов и для прямых реализаций

+0

Вот как я решил это решить, но поскольку все больше классов используют подобный подход, код становится уродливым. Наверное, у меня нет выбора. –

Смежные вопросы