【问题标题】:Anonymous Types匿名类型
【发布时间】:2010-02-19 21:15:08
【问题描述】:

我有一个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);

现在我如何解开该变量并访问这些属性??

【问题讨论】:

  • 最大的问题是你为什么要这样做?你想达到什么目的?

标签: c# anonymous-types unboxing


【解决方案1】:

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

即使您在技术上可以在声明它们的方法之外创建相同类型的实例(根据 C# 3.0 语言规范的第 7.5.10.6 节,其中指出:

在同一个程序中,两个匿名 指定一个对象初始值设定项 相同属性的序列 中的名称和编译时类型 相同的订单将产生实例 相同的匿名类型。

) 你无法获得类型的 name,你需要它来执行从 Object 到你创建的类型的转换。您将不得不求助于 cast-by-example solution,这本身就有缺陷。

Cast-by-example 是有缺陷的,因为从设计的角度来看,您想要在声明它的函数之外(并且仍然在同一个模块内)访问类型的每个地方,都必须重新有效地声明类型.

重复工作会导致设计和实施草率。

如果您使用的是 .NET 4.0,那么您可以将对象实例放在动态变量中。然而,主要缺点是缺乏成员访问的编译时验证。您很容易拼错成员的名称,然后出现运行时错误而不是编译时错误。

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

【讨论】:

    【解决方案2】:

    有几种方法。

    由于 cmets 似乎表明我建议您这样做,让我明确表示:您应该为您的对象创建一个命名类型,因为您打算传递它。

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

    另一种欺骗 .NET 为您提供正确类型的方法称为“通过示例强制转换”,它是这样的:您需要通过通用方法调用传递您的对象,该方法将返回对象为正确的类型,通过推断要返回的正确类型。

    例如,试试这个:

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

    并使用它:

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

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

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

    但是,此时您应该创建一个命名类型。

    【讨论】:

    • +1 刚刚看到关于 msdn 的评论以及如何利用它 - “如果两个或多个匿名类型以相同的顺序具有相同数量和类型的属性,编译器会将它们视为相同type 并且它们共享相同的编译器生成的类型信息。”
    • @Lasse V. Karlsen:归根结底,以身作则是一种讽刺。您实际上是在您希望访问它的模块中方法之外的每个位置重新声明类型,这违反了重用的基本原则。
    • 很不错,但是感觉很别扭。几乎是邪恶的:)
    • 我没说这是个好主意。我不确定您所说的“重新声明”是什么意思,这将在内部创建为单一类型,用于原始位置和此位置,而不是两个相似但不同的类型。但同样,这样做并不是一个好主意。然而,这是可能的。换句话说,内部代码看起来就像你所做的那样:new SomeType { ... },其中“SomeType”在两个地方都是一样的。
    • @Philippe,那是因为它……几乎是邪恶的。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

        在这两种情况下,您都不需要拆箱;那是针对值类型的。匿名类型始终是引用类型。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-31
          • 2010-09-28
          相关资源
          最近更新 更多