有没有办法将动态或匿名对象转换为强类型的声明对象?

时间:2013-06-14 04:38:06

标签: .net c#-4.0 anonymous-class dynamicobject

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

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

4 个答案:

答案 0 :(得分:42)

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

假设这是你的班级:

// 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库)。

答案 1 :(得分:12)

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

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

  • 动态类型用法编译以使用带反射的对象类型。
  • 您的代码实际上接收Object,(实际上)包含来自一个特定静态类型的值。

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

换句话说,只有当分配给动态的值是Person的基础或派生类型(为示例发明)时,以下代码才有效:

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

这就是它。

公平地说,您可以使用不安全的代码访问内存地址(如C ++)逐字节复制值,但对我而言,这并不比反射更好。

答案 2 :(得分:4)

这里我们可以将匿名对象转换为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();

答案 3 :(得分:1)

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

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

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

运行时不知道构造函数中发生了什么或类是如何在内部实现的,因此任何此类工具都会将类型安全性从水中吹走。动态的全部意义是允许duck typing / runtime dispatch / etc.

编辑:如果我误解了这个问题让我知道,但我假设你想把动态对象看作是SomeType的一个实例。

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