2017-02-19 3 views
0

Добрый день, все.C# Преобразовать общий, унаследованный тип с интерфейсом к базовому типу с тем же интерфейсом

Могу ли я спросить вас, почему это невозможно? Я изучаю интерфейс & generic сейчас, и я думаю, что это возможно, потому что Group реализует iPoppable & iPushable. Но преобразование iPoppable в группу невозможно, компилятор жалуется. Я хотел бы знать логику, почему это невозможно.

interface iPoppable<out T>{T Pop();} 
interface iPushable<in T>{void Push(T ag_t);} 

class Program 
{ 
    static void Main() 
    { 
     iPoppable<Lion> lions = new Group<Lion>(); 
     iPoppable<Animal> animals = lions; //Possible 
     Group<Lion> lions2 = lions; //Not possible 
    } 
} 

class Animal{} 
class Lion:Animal{} 

class Group<T>:iPoppable<T>, iPushable<T> 
{ 
    public void Push(T ag_t){} 
    public T Pop(){return something;} 
} 
+0

Для начала ваша подпись в вашей группе 'Group' неверна. Pop должен возвращать объект типа 'T', а не void. Также вам нужно изучить работу с ковариацией * и * контравариантность. – lintmouse

+0

Спасибо. просто исправлено. И да. Я просто читал о них обоих. –

ответ

3

Хорошо, шаг за шагом.

iPoppable<Lion> lions = new Group<Lion>(); 

работы, потому что Group реализует iPoppable и универсальный параметр T то же самое.

iPoppable<Animal> animals = lions; 

работы, потому что оба они являются iPoppable и Lion происходит от Animal. Более формально это пример covariance.

Объект, созданный с использованием аргумента более производного типа, присваивается объекту, созданному с использованием аргумента с менее производным типом. Совместимость присвоений сохраняется.

Microsoft Docs.

Group<Lion> lions2 = lions; 

Не работает, потому что вы назначаете тип интерфейса типу класса. iPoppable просто говорит, что lions имеет Lion Pop(); метод, не более! Говоря Group<Lion> lions2 = lions;, вы утверждаете, что lions2 - полнофункциональный объект Group, который будет иметь все методы и свойства Group класс. Который не обязательно true, и поэтому компилятор жалуется.

Вы можете помочь компилятору говоря

Group<Lion> lions2 = (Group<Lion>)lions; 

потому что вы знаете, за то, что особенно lions, хотя тип iPoppable фактически Group.

Чтобы проиллюстрировать, что компилятор боится, см. Следующий фрагмент.

interface iPoppable<out T> 
{ 
    T Pop(); 
} 
interface iPushable<in T> 
{ 
    void Push(T ag_t); 
} 

class Program 
{ 
    static void Main() 
    { 
     // Here, we know the truth, so we cast 
     iPoppable<bool> group = new Group<bool>(); 
     Group<bool> group2 = (Group<bool>)group; // Possible 

     // What about here? We also convert iPoppable to Group... 
     iPoppable<bool> notGroup = new NotGroup<bool>(); 
     Group<bool> notGroup2 = (Group<bool>)notGroup; // Bad... Compiler was right... 

     notGroup2.HelloGroup = true; // HA! Runtime exception. 
     // That's what compiler was worrying about. 

     // System.InvalidCastException: Unable to cast object of 
     // type 'NotGroup`1[System.Boolean]' to type 'Group`1[System.Boolean] 
    } 
} 

class Group<T> : iPoppable<T>, iPushable<T> 
{ 
    public void Push(T ag_t) { } 
    public T Pop() { return default(T); } 

    public bool HelloGroup { get; set; } 
} 

class NotGroup<T> : iPoppable<T>, iPushable<T> 
{ 
    public void Push(T ag_t) { } 
    public T Pop() { return default(T); } 

    public bool HelloNotGroup { get; set; } 
} 
+0

Добрый день, Дмитрий. Спасибо за ваше любезное объяснение. Действительно, не синтаксис, но я хотел бы знать логику! Поскольку было слишком поздно оставлять комментарий, я сначала говорю спасибо и просто начал смотреть на ваш фрагмент. Если это разрешено, я хотел бы задать вам больше вопросов в этой теме. Хорошего дня! –

+0

Я проверил ваш фрагмент, и вывод, который я достиг, заключается в том, что неявный листинг не допускается, даже несмотря на то, что реализованные интерфейсы и их тип одинаковы, поскольку явный приведение допускается в спецификации C#.Это может привести к ошибке времени выполнения, когда разный тип с теми же интерфейсами передается другому типу. Итак, желательно ли делать явный приведение в этом зоопарке? –

+0

@ Велосипедная прогулкаDog - Я рад, что мой ответ помог! Что касается вашего вопроса, давайте определим условия правильно. Неявный бросок НЕ является отличным, его тип-тип преобразования типов, который всегда преуспевает, и никакие данные не могут быть потеряны. Пример: преобразование производного типа в базовый. Явный листинг (который имеет этот синтаксис с круглыми скобками) МОЖЕТ сбой (+ потеря данных). Он МОЖЕТ бросить исключение, если правая сторона НЕ на самом деле правильного типа. Основная идея - избегать явного приведения, когда это возможно. Вы всегда можете проверить тип с отражением или поймать исключение, но это будет плохая практика. –

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