2011-02-02 4 views
1

Есть несколько отличных ресурсов на covariance and contravariance здесь, на StackOverflow, но я, кажется, неправильно понимаю основы контравариантности. Я ожидаю, что этот пример работы:Неявная контравариантность на классах - простой неудачный пример

public partial class WebForm1 : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     A a = new B(); 
     B b = new A(); 
    } 
} 

public class A 
{ 
    int id { get; set; } 
} 
public class B : A 
{ 
} 

Установка А в точку Б, которая является ковариация, но установка б на новый A терпит неудачу с ошибкой компиляции. Даже при явном приведении все еще генерирует ошибку во время компиляции. Есть ли способ сделать это или я просто полностью не понимаю контравариантность?

ответ

5

Вы не можете сделать:

B b = new A(); 

Поскольку A просто неB. Назначение недействительно. Я не уверен, что я бы назвал это отклонение - это просто наследование.

В общем случае, когда B были члены, что А не так, вы можете увидеть, что это не имеет смысла делать (если b на самом деле держит ссылку на A объекта):

b.SomeMethod(); 

где SomeMethod определяется только в B, но эта логика распространяется на присвоение самой переменной. Даже если вы добавили актерский состав, у приведения есть неявная проверка типа, которая потерпит неудачу.

+0

Спасибо за освобождение. Итак, допустим, B имеет в нем строковое название. Я хотел бы назначить всех членов от A до B, а затем назначить Title отдельно. Помимо явного назначения всех свойств по отдельности, есть ли ярлык? Это все, на чем я на самом деле. – DougJones

+0

@ Doug - Возможно, AutoMapper? Также нет ничего странного в том, чтобы использовать сериализацию в одностороннем путешествии для изменения между одинаковыми моделями, но AutoMapper, вероятно, является вашим самым легким вариантом здесь. –

+0

Отличный ... не слышал о проекте AutoMapper. Это помогает моей эффективности, но я думал о том, что неявный бросок будет работать и обеспечить эффективное выполнение. В любом случае, теперь я знаю ... еще раз спасибо. – DougJones

1

Контравариантность заключается не в нарушении правил кастинга; она применяется в ситуации, как:

void WithApple(Action<Apple> eat); 

Теперь предположим, что у вас есть какой-то метод, который знает, как есть любые фрукты:

void EatFruit(Fruit fruit); 

Поскольку он может съесть любой вид фруктов, вы должны быть в состоянии сказать:

WithApple(EatFruit); 

Это было невозможно до поддержки контравариантности, поскольку делегат должен был точно соответствовать.

Это отличается от ковариации, которая является немного более интуитивным понятием:

void EatAllFruit(IEnumerable<Fruit> inBasket); 

где вы должны быть в состоянии:

IEnumerable<Apple> apples = someBasket; 
EatAllFruit(apples); 
6

я просто совершенно неправильно контравариации?

Да. У вас есть полностью и совершенно неправильно понял, что означает «ковариация» и «контравариантность». Вы путали их с совместимостью назначения .

Это чрезвычайно распространенная ошибка. Эти два понятия связаны, но они совсем не то же самое.

Совместимость присвоений - это свойство, что выражение одного типа может быть сохранено в переменной другого типа.

Covariance - это свойство, что сопоставление типов от типов сохраняет совместимость присвоения направлений. Если Giraffe является присвоением, совместимым с Animal, и это означает, что IEnumerable<Giraffe> является присвоением, совместимым с IEnumerable<Animal>, тогда картирование IEnumerable<T> составляет covariant.

Смотрите мою статью на эту тему для более подробной информации:

http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx

Установка А в точку Б, которая является ковариационной

Да это работает. «a» соответствует присвоение совместимости с B. Это не «ковариация», потому что ничего не меняется. Нет сопоставление типов от типов к типам, которое сохраняет направление совместимости присваивания, используемое в присваивании «a = B»; ничто не является общим.

, но установка b на новый A завершается с ошибкой компиляции.

Исправить.

Есть ли способ сделать это?

№ Вместо «А» и «В» назовите их «Животное и жираф». Каждый Жираф - это Животное, поэтому, если переменная может содержать Животное, тогда он может содержать Жираф. Если вы попытаетесь пойти другим путем, вы не можете поместить Animal в переменную типа Giraffe. Животное на самом деле может быть тигром. Почему вам должно быть позволено поставить Тигра в переменную типа Giraffe?

+0

Я подозреваю, что не читаю это правильно. Вы указываете «Нет сопоставления типов от типов, которые сохраняют направление совместимости присваивания». Что относительно 'T -> IEnumerable '? Тогда, если 'T' присваивается переменной типа' U', также имеет место, что 'IEnumerable ' присваивается переменной типа 'IEnumerable '. И наоборот, если экземпляры 'T' не присваиваются переменным типа' U', то это же верно для экземпляров 'IEnumerable ' для переменных типа 'IEnumerable '. Кажется, это сопоставление типов с типами, которые сохраняют совместимость назначений. – jason

+0

@ Джейсон: Я имел в виду «такого картографирования, используемого в вашей программе». Я обновил текст. –

+0

+1 Спасибо! Это очищает ковариацию для меня. Мне просто нужно потратить больше времени на то, чтобы понять мое понимание контравариантности. – DougJones

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