2016-11-01 2 views
-2

Я думаю, что я понимаю, что дженерики не поддерживают ковариацию, поэтому первый пример не работает и дает исключение Invalid Cast. Все компилируется.В чем разница между двумя видами использования дженериков (ковариация)

Но почему работает второй пример? Я могу видеть, что это одно и то же.

MyClass как это:

public interface IGenericClass<T> { } 
public class MyClass : IGenericClass<SomeType> 
{ 
} 

не работает:

public class SendingEmail<T> 
{ 
    IGenericClass<T> abc; 
    public void Send(IGenericClass<T> _abc) 
    { 
     this.abc = _abc; 
    } 
} 

Использование:

var myClass = new MyClass(); 
SendingEmail<MyClass> sendingEmail = new SendingEmail<MyClass>(); 
sendingEmail.Send(IGenericClass<MyClass>myClass); 
//sendingEmail.Send(myClass); This was wrong 

Также пробовал:

Удалены как он никогда не компилируется


Working:

class SendingEmail 
{ 
    void Send<T>(MyGenericClass<T> abc) 
    { 

    } 
} 

Использование:

SendingEmail sendingEmail = new SendingEmail(); 
sendingEmail.Send(myclass); 
+1

Ваш нерабочий пример должен быть 'SendingEmail sendEmail = новый SendingEmail ();' - не 'myclass'. Ваш рабочий пример работает правильно, потому что он выводит 'T' правильно, т. Е. Он присваивает' T -> SomeType', а не ваш явный 'T-> myclass' – Rob

+1

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

+0

_ «Все компилируется» _ - Я не понимаю, как это сделать. Безопасность типа C# должна была исключить возможность компиляции выражения, подобного тем, которые содержатся в ваших нерабочих примерах, с ошибкой в ​​вызове 'sendEmail.Send (myClass)'. Я согласен с комментариями о том, что вы запутываете, какие параметры типа есть, но ваш вопрос принципиально не имеет смысла, поскольку в нем есть противоречивая информация. Если вы не можете исправить проблему, используя предоставленные до сих пор комментарии и ответы, исправьте вопрос, чтобы он включал в себя хороший [mcve], который делает то, что вы говорите. –

ответ

2

Первый пример не имеет ничего общего с ковариации. Вы просто сбиваете с толку то, что на самом деле T; T - SomeType, его не MyClass.

Во втором примере вы даете компилятору вывод правильного типа и поэтому он работает.

Редактировать

Редактирование на ваш вопрос не решить эту проблему, вы до сих пор смущает то, что T является: в MyClassT является SomeType. В SendingEmail<T>T Должно также be SomeType потому что abc напечатано IGenericType<T>, и вы в конечном счете хотите, чтобы это было IGenericType<SomeType>.

В вашем коде вы создаете экземпляр с кодом SendingEMail<MyClass>, который будет означать, что abc действительно напечатан IGenericType<MyClass>, что не так; Вы не можете преобразовать IGenericType<SomeType> в IGenericType<IGenericType<SomeClass>>, что вы действительно делаете при звонке sendingEMail(MyClass);

Что вам нужно сделать: var sendingEmail = new SendingEmail<SomeType>().

Об этом связано с дисперсией типа, это не так. Тип дисперсии - это то, что позволяет вам делать IEnumerable<Animal> animals = Enumerable.Emtpy<Tiger>(), и запрещает вам делать то же самое с IList<T>; IEnumerable является ковариантным в T, в то время как IList является инвариантным в T.

Обратите внимание, что C# имеет сломанную ковариацию в массивах, следующее правовое: Animal[] animals = new Tiger[3]. Это сломано, потому что теперь вы можете законно делать animals[0] = new Turtle(); и ... ох ... у вас просто есть исключение во время выполнения. Этот сценарий является именно тем, почему IList инвариантен в T. Почему C# нарушает ковариацию в массивах? Я не знаю, но считаю это неудачным (хотя, вероятно, оправданным) дизайнерским решением.

+0

Я отредактировал свой ответ и задаюсь вопросом, остается ли ваш ответ таким же. Первый пример все еще не имеет отношения к ковариации? – Carol

+0

@K_Rol см. Редактирование – InBetween

+0

Спасибо за объяснение. Это то, что я искал. Я, очевидно, знал, что я чего-то не получаю, но не знал, что. Разве это не так? Я не могу понять, почему он не получил красиво. еще раз спасибо – Carol