【问题标题】:Generics Casting泛型铸造
【发布时间】:2011-06-11 23:38:23
【问题描述】:
interface Base { ... }
class Sub : Base { ... }

class OtherBase<T> where T : Base { ... }
class OtherSub<T> : OtherBase<T> where T : Base { ... }

//...in some class
void Call<T>() where T : OtherBase<Base> { }

//...
Call<OtherSub<Sub>>(); //compile fails...

似乎在使用泛型时,编译器不会在 泛型类型(OtherBase/OtherSub)。为什么会这样?

更新: 还请解释上面和下面的区别(有效)

void Call<T>() where T : Base { }
//...
Call<Sub>();

【问题讨论】:

    标签: c# generics


    【解决方案1】:

    禁止这种行为(称为“通用方差”)是必要的,否则以下代码将编译:

    List<string> strlist = new List<string>();
    List<object> objlist = strlist;
    objlist.Add(42);
    

    我们在字符串列表中添加了一个数字。不好。 (顺便说一句,代码会为 arrays 而不是 Lists 编译,因为 Java 出于某种原因允许这样做;但是,这会引发运行时异常。)

    不过,您可以避免这种情况:

    static void Call<U, T>(T x) where U : Base where T : OtherBase<U> { }
    

    然后这样称呼它:

    Call(new OtherSub<Sub());
    

    C# 4.0 还提供了generic variance for interfaces。但是,通常不需要使用它们。

    【讨论】:

    • 这对于给定的示例很有意义,但对于方法调用仍然没有意义。您能否解释一下您的示例与“void Call() where T : Base { }”、“Call()”之间的区别?
    • @james 没错,我的错。解决了这个问题。您的扩展问题与通用方差完全无关,因此没有理由不这样做。
    【解决方案2】:

    您的问题与称为方差/协方差的概念有关。事实上,如果A 继承自BClass&lt;A&gt; 就不是Class&lt;B&gt;

    看这个例子:

    Class&lt;T&gt; 公开了一个公共方法foo(T param)

    如果Class&lt;A&gt;Class&lt;B&gt;,那么引用Class&lt;B&gt; 作为Class&lt;A&gt; 并调用foo(B param)(带有B 实例)的方法将调用foo(A param)。而B 不是A

    事实上,Class&lt;A&gt; 可以从 Class&lt;B&gt; 继承,仅当 T 仅在 Class&lt;T&gt; 中用作返回值时。

    这是在 .NET 4 中通过泛型接口的 out 关键字强制执行的。 Class&lt;T&gt; 因此可以实现 IClass&lt;out T&gt;

    【讨论】:

      【解决方案3】:

      Konrad 对如何修复您的代码提出了很好的建议。如果你想使用 C# 4 的变体,你可以这样做:

      interface IOtherBase<out T> where T : Base { }
      
      class OtherBase<T> : IOtherBase<T> where T : Base { }
      class OtherSub<T> : OtherBase<T> where T : Base { }
      
      static void Call<T>() where T : IOtherBase<Base> { }
      

      Call&lt;OtherSub&lt;Sub&gt;&gt;() 这样就可以了。

      【讨论】:

        猜你喜欢
        • 2023-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多