C#可以装箱和取消装箱通用类吗?

时间:2017-11-06 20:22:19

标签: c# generics

你可以像这样打包和取消包装类型:

List<object> items = new List<object>();
items.Add("hello");
items.Add(123);

在这里,只要它来自于对象,我们放入什么并不重要。所以这很有效。

但是可以用泛型类来做吗? 像这样:

public class Foo<T>
{
    public T MyItem;
}

static void Main()
{
    List<Foo<object>> items = new List<Foo<object>>();
    items.Add(new Foo<string>() { MyItem = "Hello" });
    items.Add(new Foo<int>() { MyItem = 123 });
}

在这里,尽管string和int是对象的类型,但它会给我一个错误。

我想到了一个简单的解决方案,那就是通过转动新的Foo&lt;字符串&gt; 进入新Foo&lt;对象&gt; ,然后只需将字符串值放入对象类型中,如下所示:

items.Add(new Foo<object>() { MyItem = "Hello" });

但是我处在一种我无法做到的情况。

那么有什么办法可以实现这个目标吗?

2 个答案:

答案 0 :(得分:3)

鉴于此课程:

public class Foo<T>
{
    public T MyItem { get; set; }
}

如果您有Foo<object>的列表,则无法向其添加Foo<int>。 如果可以,那么你可以这样做:

var myListOfFoos = new List<Foo<object>>();
myListOfFoos.Add(new Foo<int>());
Foo<object> firstFoo = myListOfFoos[0]; // this is the Foo<int> you added.
firstFoo.MyItem = "string!"; // How can you do this with a Foo<int>?

我的眼睛总是从“协变”和“逆变”这两个词中釉。编译器总是保护您免受这种情况的影响。你只需要弄清楚它是什么(正确地)保护你不要试图去做。

答案 1 :(得分:3)

尝试编译代码:

您必须创建参数T协变,这只能在接口和委托上完成。将T定义为协变量时的另一个限制因素是T不能是值类型。

文档 - out (Generic Modifier) (C# Reference)

  

对于泛型类型参数,out关键字指定type参数是协变的。您可以在通用接口和委托中使用out关键字。

     

...参考类型支持协方差和逆变,但 不支持

关于装箱/拆箱的问题在这种情况下也不适用于泛型。泛型确保类型参数永远不会装箱或取消装箱(默认情况下)。评论中有很多好的链接,我建议你仔细阅读它们,这样你就可以更好地理解1)装箱/拆箱和2)仿制药。

这是您可以使用代码获得的最接近的

static void Main() {
  List<IFoo<object>> items = new List<IFoo<object>>();
  items.Add(new Foo<string>() { MyItem = "Hello" });


  // not possible because int is a value type
  // items.Add(new Foo<int>() { MyItem = 123 }); 
}

interface IFoo<out T>
{
    T MyItem {get;}
}
class Foo<T> : IFoo<T>
{
    public T MyItem {get;set;}
}