匿名类型

6

我有一个类似于Dictionary(TKey, TValue)的东西

Dictionary<int, ArrayList> Deduction_Employees = 
    new Dictionary<int, ArrayList>();

之后,我向该数组列表中添加了一个匿名类型,如下所示

var day_and_type = new {
    TheDay = myDay,
    EntranceOrExit = isEntranceDelay
};

Deduction_Employees[Employee_ID].Add(day_and_type);

现在我如何打开那个变量并访问这些属性?

4
为什么你想这样做?你想实现什么目标? - pdr
5个回答

13

首先,您没有拆开类型。匿名类型是引用类型,不是结构体。

尽管您可以在声明它们的方法之外的地方创建相同类型的实例(根据C# 3.0语言规范第7.5.10.6节的规定:

在同一个程序中,指定相同名称和编译时类型顺序的属性序列的两个匿名对象初始化程序将生成相同的匿名类型实例。

),但您无法获取类型的名称,而您需要这样做才能执行从Object回到创建的类型的转换。您必须采取 inherently flawed 的cast-by-example solution

按示例转换是有缺陷的,因为从设计的角度来看,在您希望在函数之外访问该类型的每个位置(仍在同一模块内)时,您必须重新声明该类型。

这是一种导致设计和实现混乱的工作重复。

如果您使用.NET 4.0,则可以将对象实例放在动态变量中。然而,最大的缺点是缺少成员访问的编译时验证。您可能会轻易地拼写成员名称,然后就会出现运行时错误而非编译时错误。

最终,如果您发现需要在声明它的方法之外使用匿名类型,则唯一的好解决方案是创建一个具体类型,并将匿名类型替换为具体类型。


8
有几种方法。
由于评论似乎表明我建议您这样做,让我澄清一下:您应该为对象创建一个命名类型,因为您打算传递它。 首先,您可以使用Reflection,另一个答案已经指出了这一点。
另一种方法是“按示例转换”,这会欺骗.NET并给您正确的类型。具体来说,您需要通过一个通用方法调用传递对象,该方法将根据推断出的正确类型返回对象。
例如,尝试这个:
private static T CastByExample<T>(T example, object value)
{
    return (T)value;
}

并且要使用它:

var x = CastByExample(new { TheDay = ??, EntranceOrExit = ?? }, obj);

对于这两个 ?? 位置,您只需要传递符合这些属性数据类型的内容,这些值将不会被使用。

这利用了一个事实,即包含完全相同属性(类型相同、顺序相同)的多个匿名类型,在同一程序集中将映射到同一单个类型。

然而,这时候您应该创建一个命名类型。


刚看到 MSDN 上的评论,想到了如何利用它 - “如果两个或更多匿名类型在相同顺序下具有相同数量和类型的属性,则编译器将它们视为相同类型,并共享相同的编译器生成的类型信息。” - Kobi
@Lasse V. Karlsen:最终,按示例转换是可耻的。你实际上是在每个方法外部重新声明类型,违反了重用的基本原则。 - casperOne
非常好,但感觉非常尴尬。几乎是邪恶的 :) - Philippe Leybaert
我没有说这是一个好主意。虽然我不确定你所说的"redeclaring"是什么意思,但它将在内部被创建为一个单一类型,在原始位置和当前位置都会使用它,而不是作为两个相似但不同的类型。但是再次强调,这并不是一个好主意。然而,这是可能的。换句话说,内部代码看起来就像你所做的那样:new SomeType { ... },其中"SomeType"在两个地方都是相同的。 - Lasse V. Karlsen
无论你想把这称为“重新声明”还是其他名称,它仍然具有与冗余类型定义相同的潜在单一定义规则违规和结果破坏的可能性。 - Ben Voigt
显示剩余4条评论

3
一个匿名类型具有方法作用域。要将匿名类型或包含匿名类型的集合传递到方法边界之外,您必须首先将该类型转换为对象。然而,这会破坏匿名类型的强类型。如果必须存储查询结果或将其传递到方法边界之外,请考虑使用普通命名的结构体或类,而不是匿名类型。
来源:http://msdn.microsoft.com/en-us/library/bb397696.aspx

1
不行,你只能通过反射来访问属性。编译器无法知道类型是什么,而且由于它是匿名类型,你也无法进行强制转换。

1

如果您使用的是 .NET 1.x - 3.x 版本,您必须使用反射。

如果您使用的是 .NET 4.0 版本,您可以使用动态类型并调用所需的属性。

在任何情况下,您都不需要取消装箱;这只适用于值类型。匿名类型始终是引用类型。


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