56

如果我有一个动态对象或匿名对象,其结构与强类型对象的结构完全匹配,是否有.NET 方法可以从动态对象构建类型对象?

我知道我可以使用 LINQdynamicList.Select(dynamic => new Typed { .... }类型的东西,或者我可以使用 Automapper,但我想知道是否没有专门为此构建的东西?

4

5 回答 5

65

您可以序列化为中间格式,然后立即对其进行反序列化。这不是最优雅或最有效的方式,但它可能会完成您的工作:

假设这是您的课程:

// Typed definition
class C
{
    public string A;
    public int B;
}

这是您的匿名实例:

// Untyped instance
var anonymous = new {
    A = "Some text",
    B = 666
};

您可以将匿名版本序列化为中间格式,然后再次将其反序列化为类型化版本。

var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var json = serializer.Serialize(anonymous);
var c = serializer.Deserialize<C>(json);

请注意,只要往返是对称的,这在理论上对于任何序列化器/反序列化器( XmlSerializer 、二进制序列化、其他 json 库)都是可能的。

于 2013-06-26T14:05:10.353 回答
18

您的问题归结为一个问题:我可以将一个静态类型变量转换为另一个静态类型变量(来自不同的继承链)吗?显然,答案是否定的。

为什么你的问题归结为上述问题?

  • 动态类型使用编译为使用带有反射的 Object 类型。
  • 您的代码实际上接收 Object,它(实际上)包含来自一种特定静态类型的值。

因此,实际上,您的代码正在处理静态类型的值,分配给对象,并在编译时被视为动态。因此,您可以将一个静态类型的值转换为另一个 [无需反射] 的唯一情况是它们是同一继承链的一部分。否则,您必然会显式地(由您编写)或隐式地使用反射(由 MS 编写并使用动态用法)。

换句话说,只有当分配给动态的值是派生自 Person 或者是 Person 本身时,以下代码才能在运行时工作(否则转换为 Person 将引发错误):

dynamic dPerson = GetDynamicPerson();
Person thePerson = (Person)dPerson;

差不多就是这样。

公平地说,您可以使用访问内存地址的不安全代码(如在 C++ 中)逐字节复制值,但这对我来说没有什么比反射更好的了。

于 2013-06-25T16:47:00.937 回答
9

在这里我们可以将匿名对象转换为 Dictionary

Dictionary<string, object> dict = 
    obj.GetType()
      .GetProperties()
      .ToDictionary(p => p.Name,  p => p.GetValue(obj, null));

您也可以使用LINQ投射对象:

List<MyType> items = anonymousType.Select(t => new MyType(t.Some, t.Other)).ToList();
于 2013-06-25T17:57:16.120 回答
1

如果您的对象继承自 MarshalByRefObject,您可以使用 RealProxy。

另一种选择是使用反射,但您可能会受到未标记为虚拟的东西的限制和/或必须使用接口。您也可以让它复制值,假设属性是可写的并且空构造函数适用于您的情况。

您的问题的实际答案是否定的,除非动态对象是该类型的实例,否则没有自动方法将动态对象视为特定类型,也没有任何自动工具可以将动态/匿名对象中的值复制到命名类的实例。

运行时不知道构造函数中发生了什么,也不知道类是如何在内部实现的,所以任何这样的工具都会破坏类型安全。动态的重点是允许鸭子打字/运行时调度/等。

编辑:如果我误解了这个问题,请告诉我,但我假设您想将动态对象视为 SomeType 的实例。

在我自己的项目中,我为此使用了一个 Object Mapper 类,它匹配可写属性和相同或强制类型的属性名称,因此至少我不必编写 10,000 行样板文件,尽管我的来源不是t 动态,所以我使用 Reflection.Emit/DynamicMethod 来大大加快它的速度。

于 2013-06-24T05:32:12.740 回答
0

因此,我将为这个问题提供一个答案,假设您将手动设置原始变量。假设您有一个Dictionary<string, dynamic> dict包含 和 的动态版本float xbool y. 你可以做:

float x = (float)dict["x"];
bool y = (bool)dict["y"];

如果您想对引用类型执行此操作,您可以简单地为您的类创建一个构造函数,为每个字段执行此转换。

于 2022-02-17T18:55:36.580 回答