泛型和匿名类型

3
我理解,通常泛型用于编译时的安全性,并允许我们保持强类型集合。那么泛型如何允许我们存储匿名类型?
List<object> TestList = new List<object>();
TestList.Add(new { id = 7, Name = "JonSkeet" });
TestList.Add(new { id = 11, Name = "Marc Gravell" });
TestList.Add(new { id = 31, Name = "Jason" });

@nettguy - 奇怪的是您使用了这里的成员来填充您的列表。 - JonH
1
即使匿名类型也派生自Object - Dan Puzey
1
澄清:除了指针类型之外,所有东西都可以转换为对象。并非所有东西实际上都是从对象派生的。http://blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx - Anthony Pegram
3个回答

9

其他人已经解释了为什么你的代码有效——你的示例是强类型的,因为每个元素都是一个对象,但这意味着它并不是非常有用。你不能从列表中取出元素并访问例如它们的Name属性,因为它们只是对象,所以这在一般情况下是无法工作的。

然而,可以创建一个匿名类型的强类型List——只需要使用像这样的小实用程序方法:

static List<T> CreateList<T>(params T[] items) {
  return items.ToList();
}

问题在于您无法在不提供类型名称的情况下调用构造函数。在调用方法时,C# 可以推断类型参数,因此您可以编写以下代码:
var testList = CreateList(
  new { id = 7, Name = "JonSkeet" },
  new { id = 11, Name = "Marc Gravell" });
testList.Add(new { id = 31, Name = "Jason" });

这是完全类型安全的,例如您可以编写testList[0].Name来获取第一个人的姓名。如果您尝试编写类似于testList.Add(42)的内容,您将会得到一个编译时错误,因为该列表被强类型化为仅包含具有idName属性的匿名类型。


非常有趣,说得非常好。我确实在想,在除了作为“混淆”代码的形式之外,你会希望使用“匿名对象”的列表的真实世界场景是什么。肯定还有其他的“aha”时刻等待着我们去发现 :) - BillW
@BillW:这是一种方便的方式;它可以避免你定义自己的小助手类型。现在框架中有一个标准的Tuple类型,使用匿名类型列表的用例变得更加弱了。 - Eric Lippert
1
@Martinho:这不应该很难(当然,C#比大多数人预期的要复杂,但仍然...)。您已经可以在方法调用中省略类型参数-例如a.Foo(1)而不是a.Foo<int>(1)。我正在寻求类似构造函数的东西-例如new List<?> { 1, 2, 3 }而不是new List<int> { 1, 2, 3 }。(?将是一个特殊符号-类似于var)。 - Tomas Petricek
1
@Tomas:是的,对于那些例子来说,这样做很好,但是你如何在“var foo = new List<?>()”上进行类型推断呢?可能吗?毫无疑问。F#可以做到,Haskell也可以。值得C#团队付出努力吗?我不知道。我不确定他们会不会高兴地发布一个只覆盖了一半情况的功能,特别是调用默认构造函数可能相当普遍 :( - R. Martinho Fernandes
1
@Martinho:我不会允许这样做——C#中的类型推断仅适用于表达式范围。F#或Haskell使用非常不同的方法。我的情况实际上是有问题的,因为它使用基于Add方法(由对象初始化器使用)而不是直接使用构造函数的推断,所以需要一些努力。我想这并不是很有用,但有了它会很好:-)。 - Tomas Petricek
显示剩余4条评论

8

这是因为object是.Net中所有实例的根类型。 因此,任何表达式都可以用于期望object的位置,因为它们都满足System.object的基本契约。

例如,以下内容完全合法。

List<object> TestList = new List<object>();
TestList.Add(new { id = 7, Name = "JonSkeet" });
TestList.Add("Foo");
TestList.Add(42);

如果你没有一个可以引用的声明类型,你如何将第一个项目转换回去? - jocull

6

因为所有的东西都是(或可以被装箱成)一个对象,那就是一组对象列表


严谨地说,应该写成“或者可以被转换为”。 - SolutionYogi

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