Почему вариативность .NET 4 для аргументов универсального типа не распространяется также и на классы?

Возможные дубликаты:
Почему в C # 4.0 нет общей вариации для классов?
Почему C # (4.0) не допускает ко- и контравариантности в типах универсальных классов?

Новая ко- и контравариантность .NET 4.0 для аргументов универсального типа работает только для интерфейсов и делегатов. В чем причина того, что его не поддерживают и для классов?


person bitbonk    schedule 29.09.2010    source источник
comment
Не уверен, о чем вы здесь говорите, ковариация и контравариантность поддерживаются в классах: см. Это сообщение в блоге: blogs.msdn.com/b/wriju/archive/2009/07/31/   -  person Lazarus    schedule 29.09.2010
comment
В этой статье просто показаны различия для делегатов.   -  person bitbonk    schedule 29.09.2010
comment
Кто проголосовал за закрытие? Неправильный вопрос? Это отличный вопрос ...   -  person Thomas Levesque    schedule 29.09.2010
comment
Ага! :) На самом деле Stackoverflow - это полный вопрос, когда люди пытались применить новую вариацию к классам (и, естественно, потерпели неудачу).   -  person bitbonk    schedule 29.09.2010
comment
Связанные вопросы: goo.gl/4PEW goo.gl/R61S goo.gl/S7No   -  person bitbonk    schedule 29.09.2010
comment
см. также stackoverflow.com/questions/2541467/, на который есть ответ Эрика Липперта (члена команды MS C #)   -  person Ian Ringrose    schedule 29.09.2010
comment
Да это дубликат. Мы можем закрыть это сейчас.   -  person bitbonk    schedule 29.09.2010
comment
Это просто упущение со стороны команды Microsoft VM, когда они впервые разработали систему типов CLR. Я предполагаю, что они хотели бы поддержать это, но этого просто не было изначально, и изменение виртуальной машины на столь позднем этапе цикла таким фундаментальным образом могло бы быть слишком опасным. Ситуация сравнима с Generics в Java. Это всего лишь хитрость, чтобы перенести некоторые упущения в язык. И JVM, и CLR имеют некоторые недостатки дизайна: JVM не знает Generics (но поддерживает ко- / контравариантные классы); CLR имеет некоторую базовую поддержку Generics (без высокодородных типов), но не поддерживает вариативность.   -  person soc    schedule 30.09.2010
comment
@soc, я сомневаюсь, что это недосмотр, это выбор дизайна ... Вы читали ответ на этот вопрос?   -  person Thomas Levesque    schedule 30.09.2010
comment
@ Томас: Да, есть. Дисперсия - это не черная магия, эту концепцию хорошо понимают на протяжении веков и уже десятки раз доказывают, что она работает. Фактически, с помощью дисперсии и лучшего компилятора можно обнаруживать ошибки во время компиляции, которые раньше привели бы к необнаруженной ошибке во время выполнения. Следовательно, поддержка реальной дисперсии может сделать программы более правильными. Подход .NET - это такое же оправдание, что и Generics в Java; и меня раздражает то, что нет основной виртуальной машины, которая не использовала бы подход к проектированию систем типов, который бы не использовал подход «давайте просто разберемся вместе».   -  person soc    schedule 01.10.2010


Ответы (2)


Для обеспечения безопасности типов C # 4.0 поддерживает ковариацию / контравариантность ТОЛЬКО для параметров типа, отмеченных как in или out.

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

public class Stack<T>
{
  int position;
  T[] data = new T[100];
  public void Push (T obj)   { data[position++] = obj;  }
  public T Pop()             { return data[--position]; }
}

Было бы невозможно аннотировать T как на выходе, потому что T используется как во входных, так и в выходных позициях. Следовательно, этот класс никогда не может быть ковариантным или контравариантным - даже в C # поддерживаются параметры ковариантного / контравариантного типа для классов.

Интерфейсы прекрасно решают проблему. Мы можем определить два интерфейса, как показано ниже, и сделать так, чтобы Stack реализовал оба:

public interface IPoppable<out T> { T Pop(); }
public interface IPushable<in T> { void Push (T obj); }

Обратите внимание, что T ковариантен для IPoppable и контравариантен для IPushable. Это означает, что T может быть ковариантным или контравариантным - в зависимости от того, приводите ли вы к IPoppable или IPushable.

Другая причина того, что ковариация / контравариантность будет иметь ограниченное использование с классами, состоит в том, что она исключает использование параметров типа в качестве полей, потому что поля фактически допускают операции ввода и вывода. Фактически, было бы сложно написать класс, который бы делал что-либо полезное, с параметром типа, помеченным как in или out. Даже в простейшем случае написания ковариантной реализации Enumerable возникнет проблема - как бы с самого начала получить исходные данные в экземпляр?

person Joe Albahari    schedule 29.09.2010
comment
Тип класса, который принимает параметры типа T в конструкторах, но не имеет другого метода экземпляра, и имеет метод, возвращающий тип T, теоретически может быть ковариантным в T без каких-либо проблем с безопасностью типов. Сложность связана со статическими переменными. Если класс Thing<T> имеет общедоступное статическое поле Foo типа int, Thing<BaseType> будет иметь Foo отличное от Thing<DerivedType>. - person supercat; 20.10.2012

Команда .NET вместе с командой C # и VB.NET имеет ограниченные ресурсы, работа, которую они проделали над ко- и контравариантностью, решает большую часть реальных проблем. Системы типов очень сложно получить правильно - решение, которое работает в 99,9999% случаев, недостаточно хорошо, если оно приводит к небезопасному коду в других случаях.

Я не думаю, что затраты / время на поддержку спецификаций ко- и контравариантности (например, «вход» / «выход») для методов класса имеют достаточно большое значение. Я вижу очень мало случаев, когда они могут быть использованы - из-за отсутствия наследования множественных классов.

Вы бы предпочли подождать еще 6 месяцев для домена .net, чтобы получить эту поддержку?


Еще один способ подумать об этом: в .net

  • Интерфейсы / делегаты - используются для моделирования системы концептуальных типов приложения.
  • Класс используются для реализации вышеуказанных типов.
  • Наследование классов используется для уменьшения дублирования кода при выполнении вышеуказанных действий.
  • ко- и контравариантность касается системы концептуальных типов приложения.
person Ian Ringrose    schedule 29.09.2010