Как привести мои шаблонные унаследованные классы в C #? - PullRequest
0 голосов
/ 09 апреля 2019

У меня есть класс A, который унаследован от шаблонного класса: M<C, D> и класса C : T<D> При выполнении A это класс с типом M<C, D>, но не класс с типом M<T<D>,D>, и я нене понимаю почему.Есть способ получить эту корреспонденцию?

Я использую LTS Unity 2017.4.

public class ContentItemModule<C,D> where C : ContentItem<D> where D : A_Data { }

public class ImplementedContentItemModule : ContentItemModule<ImplementedContentItem , ImplementedData> { }
public class ContentItem<D> where D : A_Data { }

public class ImplementedContentItem : ContentItem<ImplementedData> { 

    ImplementedContentItemModule _contentItemModule;

    public void Init() {
         Console.Log(_contentItemModule is ImplementedContentItemModule); // print True
         Console.Log(_contentItemModule is ContentItemModule<ImplementedContentItem, ImplementedData>); // print True
         Console.Log(_contentItemModule is ContentItemModule<ContentItem<ImplementedData>, ImplementedData>); // print False, WHY ?
    }
}

Я ожидаю, что третий журнал возвращает True, но возвращает False.

Примечание. Для одного ImplementedData существует только один ImplementedContentItem.

Есть ли ключевое слово, которое может помочь мне (или другим способом), или невозможно узнать, является ли мой _contentItemModule ContentItemModule,ImplementedData>

1 Ответ

0 голосов
/ 09 апреля 2019

Проблема в том, что генерики не следуют тем же правилам присваивания, что и обычные классы. Чтобы универсальный класс мог быть назначен, типы должны точно соответствовать. Вот пример, чтобы показать вам, почему:

Предположим, у нас есть:

class A { }
class B: A { }

полиморфизм говорит, что мы можем назначить экземпляры B переменной типа A. Это потому, что B является A. Теперь рассмотрим список:

var a_s = new List<A>();
a_s.Add(new A());
var b_s = (List<B>)a_s;
var b = b_s[0]; // But b_s[0] is the same as a_s[0], which is an A instance, and A's can't be assigned to B's!! What happened?!

Вот почему универсальные классы должны точно совпадать. Подходят более специализированные входы, так как они могут автоматически up приводиться к соответствующему типу. Однако, более специализированных выходов нет - вы не можете вниз привести к небрежности, что и происходит в (гипотетическом) коде выше. Это очевидно в языках с разным синтаксисом upcast и downcast, таких как static_cast и dynamic_cast в C ++ и :> и :?>.

в F ++.

Это различие между типами ввода и вывода действительно важно и формализовано в C # как in и out универсальные параметры, соответствующие понятиям ковариации и контравариантности. Это относится только к интерфейсам.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...