将泛型<B>转换为泛型<A>,其中B:A,使用C#进行转换。

8

我有两个类,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.TreeNode1[MSUA.GraphViewer.GraphControls.MaterialConfigControl]'的对象强制转换为类型'MSUA.GraphViewer.GraphControls.TreeNode1[MSUA.GraphViewer.PopulatableControl]'。

3个回答

7

这是泛型中的类型逆变。

虽然BA的子类型,但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>)


基本上将Generic<B>转换为Generic<A>意味着Generic<(A)Generic<B>.B>(),但这并没有帮助,因为B被强制转换为A,但仍然是B。无论如何,非常好的答案,你绝对是正确的,不过要解决这个问题还是很困难的。 - Roy T.
@Roy T 你可以尝试使用“隐式转换运算符”http://msdn.microsoft.com/zh-cn/library/z5z9kes2.aspx - StuperUser
1
@StuperUser,我会看一下隐式操作符。还要注意的是,在VS2010中,您可以使用泛型逆变性修饰符:http://msdn.microsoft.com/en-us/library/dd469484(VS.100).aspx,它允许逆变性,但不幸的是,我仍然停留在2008/.NET 3.5。 - Roy T.
哦,太酷了@oleskii。我误解了接口与逆变的工作方式。已删除我的错误评论。 - StuperUser
1
@oleksii:这能够工作是因为IEnumerable<out T>T上是协变的(请参见下面我的答案)。不幸的是,这仅适用于.NET 4.0。在.NET 3.5中,该代码将无法编译。 - InBetween
显示剩余2条评论

5
如果您的泛型类MyGeneric<T>可以实现一个对于T是协变的interface,那么您可以执行以下操作:
  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>
    }
    

编辑: 在评论中看到您正在使用 .NET 3.5,所以很遗憾这种方法在您的情况下不起作用。我将保留答案,以防对其他人有用。抱歉,我错过了这个重要的信息。


虽然这是一个很好的答案,可以解决我的问题在2010年,但我忘了在实际问题中提到我被困在2008/.NET.3.5 :) - Roy T.

1

大多数一些通用类都有一个cast< T >函数,可以为您完成此操作。如果不存在,您可以尝试创建自己的函数。


3
我并不知道大多数通用类都有一个"Cast<T>"函数,但我知道为序列定义了一个"Cast<T>"扩展方法,它尝试转换序列中的每个项。您的回答似乎暗示这是通用模式的一部分,但实际上并非如此。请注意,“am not”和“am”表示相反的意思。 - Anthony Pegram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接