【问题标题】:Why can't you cast a constrained open generic typed to the constrained type?为什么不能将一个受约束的开放泛型类型转换为受约束类型?
【发布时间】:2010-07-03 22:57:57
【问题描述】:

我想我一定是遗漏了什么,为什么我不能编译这个:

class Foo<T> where T : Bar
{
    T Bar;
}

abstract class Bar
{ }

class MyBar : Bar
{ }

static void Main(string[] args)
{
    var fooMyBar = new Foo<MyBar>();
    AddMoreFoos(fooMyBar);
}

static void AddMoreFoos<T>(Foo<T> FooToAdd) where T : Bar
{
    var listOfFoos = new List<Foo<Bar>>();
    listOfFoos.Add(FooToAdd); //Doesn't compile
    listOfFoos.Add((Foo<Bar>)FooToAdd); //doesn't compile
}

【问题讨论】:

    标签: c# generics


    【解决方案1】:

    在这里使用列表会让事情变得比实际需要的更混乱......这样最容易看到效果:

    // This won't compile
    Foo<Bar> fooBar = new Foo<MyBar>();
    

    鉴于这无法编译,因此您不能将 Foo&lt;MyBar&gt; 添加到 List&lt;Foo&lt;Bar&gt;&gt; 也就不足为奇了

    那么为什么Foo&lt;MyBar&gt; 不是Foo&lt;Bar&gt;?因为泛型类不是协变的。

    泛型变体仅在 C# 4 中引入 - 它仅适用于接口和委托。所以你可以(在 C# 4 中)这样做:

    IEnumerable<MyBar> x = new List<MyBar>();
    IEnumerable<Bar> y = x;
    

    但你做不到:

    IList<MyBar> x = new List<MyBar>();
    IList<Bar> y = x;
    

    我有一个关于方差的完整讨论,您可以从 NDC 2010 video site 下载 - 只需搜索“方差”。

    【讨论】:

      【解决方案2】:

      它无法编译,因为如果您使用 Foo&lt;int&gt; 调用您的方法,那么调用将失败:您正试图为泛型参数假定特定类型。

      您需要改用var listOfFoos = new List&lt;Foo&lt;T&gt;&gt;(),然后Add 应该可以工作。

      (编辑:同样,如果您使用 Foo&lt;T&gt;,演员也可以工作 - 但您仍然不能在代码中假设 TBar)。

      【讨论】:

      • '如果你用 Foo 调用你的方法,那么调用将失败' => 但是由于通用约束,这个调用不会编译,其中 T : Bar,不是吗?但是,为 new List>() +1 因为这实际上解决了我的真正问题!
      • 关于约束的要点。如果我解决了你的问题,你为什么接受另一个答案感到困惑......(Jon Skeet 与否!;-))
      猜你喜欢
      • 2012-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多