C # Casting Generic <B>to Generic <A>, где B: A - PullRequest
8 голосов
/ 15 июля 2011

У меня есть два класса, MyClassA и MyClassB. MyClassB наследуется от MyClassA. Я написал метод со следующей подписью

public void DoSomething(MyGeneric<MyClassA> obj);

У меня также есть следующий обработчик событий.

public void MyEventHandler(Object source, EventArgs e)
{
   //source is of type MyGeneric<MyClassB>
   DoSomething((MyGeneric<MyClassA>)obj);
}

Я понимаю, что MyGeneric<MyClassA> не относится к тому же типу MyGeneric<MyClassB>, но, поскольку MyClassB является подклассом MyClassA, есть ли способ заставить эту работу работать?

Для справки, точное сообщение об ошибке:

Невозможно привести объект типа 'MSUA.GraphViewer.GraphControls.TreeNode 1[MSUA.GraphViewer.GraphControls.MaterialConfigControl]' to type 'MSUA.GraphViewer.GraphControls.TreeNode 1 [MSUA.GraphViewer.PopulatableControl].

Ответы [ 3 ]

7 голосов
/ 15 июля 2011

Это противоречие типов в генериках.

Даже если B является подтипом A,
Generic<B> не является подтипом Generic<A>,
, поэтому вы не можете привести Generic<B> к Generic<A>.

Проверьте: http://msdn.microsoft.com/en-us/library/dd799517.aspx для более подробной информации.

Вы можете перегрузить DoSomething() к DoSomething(Generic<B>), этот метод может преобразовать Generic<B> в Generic<A> и вызвать DoSomething(Generic<A>).

5 голосов
/ 15 июля 2011

Если ваш универсальный класс MyGeneric<T> может реализовать interface, который является ковариантным в T, то вы можете сделать следующее:

  1. Определить ковариантный интерфейс в T:

    public interface IMyGeneric<out T>
    {
        T Foo();
    }
    

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

  2. Создайте свой класс MyGeneric<T> реализуйте IMyGeneric<out T>.

  3. Теперь через interface, который является ковариантным в T, действует следующий код:

    IMyGeneric<MyClassB> classBGeneric = new MyGeneric<MyClassB>();
    IMyGeneric<MyClassA> classAGeneric = classBGeneric;
    

    Итак, в вашем случае вы могли бы написать следующее:

    public void MyEventHandler(object source, EventArgs e)
    {
        DoSomething((IMyGeneric<MyClassA>)source); //IMyGeneric<MyClassB> is implicitly convertible to IMyGeneric<MyClassA>
    }
    

EDIT : просто прочитайте в комментариях, что вы работаете с .NET 3.5, поэтому, к сожалению, это не сработает в вашем случае. Я оставлю ответ на тот случай, если он кому-нибудь пригодится. Извините, я пропустил эту важную информацию.

1 голос
/ 15 июля 2011

Большинство В некоторых общих классах есть функция приведения , которая делает это за вас.Если он не существует, вы можете попробовать создать свой собственный.

...