2010-02-19 249 views
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); 

现在我怎样才能拆箱是var和访问这些属性?

+4

最大的问题是你为什么想要?你想达到什么目的? – pdr

回答

13

首先,你不拆箱的类型。匿名类型是引用类型,而不是结构。

即使技术上可以创建他们在被宣布的方法之外的相同类型的实例(如每节的C#3.0语言规范,其中规定7.5.10.6:

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

)您无法获得该类型的名称,您需要将其从Object转换回您创建的类型。你将不得不求助于本质上有缺陷的cast-by-example solution

由于从设计的角度来看,Cast-by-Example存在缺陷,您希望在声明的函数外部访问该类型的每个位置(并且仍位于同一模块内),因此必须全面有效地声明类型再次。

这是一次重复的努力,导致了sl design的设计和实施。

如果您使用的是.NET 4.0,那么您的可能将放置在一个动态变量中。但是,主要的缺点是缺少成员访问的编译时验证。你可能很容易拼错成员的名字,然后你有运行时错误而不是编译时错误。

最终,如果您发现需要在声明的方法之外使用匿名类型,那么唯一的好方法是创建一个具体类型并用匿名类型替代具体类型。

1

不,你不能。您只能使用反射访问属性。编译器无法知道类型是什么,并且由于它是匿名类型,因此无法将其转换。

1

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

如果您使用.NET 4.0,则可以使用动态类型并调用期望的属性。

在这两种情况下你都不需要unbox;这是价值类型。匿名类型始终是引用类型。

3

一个匿名类型有方法范围。要在方法边界外传递匿名类型或包含匿名类型的集合,必须先将类型转换为对象。但是,这打破了匿名类型的强类型。如果您必须存储查询结果或将其传递到方法边界之外,请考虑使用普通的命名结构或类而不是匿名类型。

来源:http://msdn.microsoft.com/en-us/library/bb397696.aspx

8

有几种方法。

由于评论似乎表明我建议你这样做,所以让我说清楚:你应该为你的对象创建一个命名类型,因为你打算传递它。

首先,您可以使用反射,这里的另一个答案已经指出。

另一种方法,它让技术.NET给你正确的类型被称为“按例转换”,它是这样的:你需要通过一个通用的方法调用传递你的对象,这将返回对象作为正确的类型,通过推断正确的类型返回。

例如,试试这个:

private static T CastByExample<T>(T example, object value) 
{ 
    return (T)value; 
} 

,并使用它:

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

两个?点,你只需要传递适合这些属性的数据类型的东西,这些值就不会被使用。

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

但是,到目前为止,您应该创建一个指定类型。

+0

+1刚才看到对msdn的评论以及如何利用它 - “如果两个或多个匿名类型具有相同顺序的相同数量和类型的属性,编译器将它们视为相同类型,并且它们共享相同的编译器生成的类型信息“。 – Kobi

+0

@Lasse V. Karlsen:最终,以身作则是一个讽刺。您有效地在您希望访问的模块中的方法之外的每个地方重新声明该类型,违反了重用的基本原则。 – casperOne

+0

非常好,但感觉很尴尬。几乎是邪恶:) –