开发者

C# Casting Generic<B> to Generic<A> where B : A

开发者 https://www.devze.com 2023-03-21 00:22 出处:网络
I\'ve got two classes, MyClassA and MyClassB. MyClassB inherits from MyClassA. I\'ve written 开发者_运维知识库a method with the following signature

I've got two classes, MyClassA and MyClassB. MyClassB inherits from MyClassA. I've written 开发者_运维知识库a method with the following signature

public void DoSomething(MyGeneric<MyClassA> obj);

I've also got the following event handler.

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

I understand that MyGeneric<MyClassA> is not of the same type MyGeneric<MyClassB> but since MyClassB is a subclass of MyClassA is there still a way to make this work?

For reference, the exact error message:

Unable to cast object of type 'MSUA.GraphViewer.GraphControls.TreeNode1[MSUA.GraphViewer.GraphControls.MaterialConfigControl]' to type 'MSUA.GraphViewer.GraphControls.TreeNode1[MSUA.GraphViewer.PopulatableControl]'.


This is type contravariance in generics.

Even though B is a subtype of A,
Generic<B> is not a subtype of Generic<A>,
so you can't cast Generic<B> to Generic<A>.

Check: http://msdn.microsoft.com/en-us/library/dd799517.aspx for more details.

You can overload DoSomething() to DoSomething(Generic<B>), this method can then convert Generic<B> to Generic<A> and call DoSomething(Generic<A>).


If your generic class MyGeneric<T> can implement an interface which is covariant in T then you could do the following:

  1. Define an interface covariant in T:

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

    This means that the generic type T can only be an output type (can not be part of a method signature defined in the interface.)

  2. Make your class MyGeneric<T> implement IMyGeneric<out T>.

  3. Now through the interface, which is covariant in T, the following code is valid:

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

    So in your case, you could write the following:

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

EDIT: Just read in comments that you are working with .NET 3.5, so sadly this won't work in your case. I'll leave the answer in case it is of any use to somebody else. Sorry, I missed that important piece of information.


Most Some generic classes have a cast< T > function which does it for you. If it doesn't exist you could try to create your own.

0

精彩评论

暂无评论...
验证码 换一张
取 消