C# 中的动态类型

假如你要构建一个人对象,通常情况下应该定义名字,地址,出生年月等。但是在运行中可能会出现你需要使用一些人对象没有包含的字段或者属性。比如还需要学历,婚姻状况等。

那么如何在运行中构建一个对象,且系统事先不知道该对象有什么属性,支持什么方法。

在.NET Framework 4.0 中提供了两个类 一个是DynamicObject, 另一个是 ExpandoObject

DynamicObject

DynamicObject 基类提供了在运行时为类添加动态功能。如果需要自定义动态对象需要继承此基类。

DynamicObject 实现IDynamicMetaObjectProvider, 使用这个接口可以在不同的支持CLR 的语言间共享自定义的动态对象,比如在 C# 语言和 VB.NET 语言间共享自定义对象。

注意:

  1. 不能直接实例化DynamicObject 类,必须从其继承。
  2. 在C# 中,需要使用 dynamic 关键字来使用从DynamicObject继承的类

在继承时,根据需要覆写基类DynamicObject类的相应方法。

TryGetMember: 动态添加Property 的Get方法

TrySetMember: 动态添加Property 的 Set方法

TryInvokeMember: 动态添加方法. 可以把一个方法赋值给委托然后把委托赋值给动态对象的方法名

还有很有类似的方法,如:TryConvert, TryBinaryOperation, TryCreateInstance, TryDeleteIndex,TryGetIndex,TryInvoke,TryUnaryOperation.

更多信息请阅读:

http://msdn.microsoft.com/zh-cn/library/system.dynamic.dynamicobject.aspx

public class DynamicPerson : DynamicObject

{

// Inner Dictionary

Dictionary<string, object> dictionary = new Dictionary<string, object>();

/// <summary>

/// If you try to get a value of Property not defined in class, this method is called

/// </summary>

/// <param name="binder"></param>

/// <param name="result"></param>

/// <returns></returns>

public override bool TryGetMember(GetMemberBinder binder, out object result)

{

string name = binder.Name.ToLower();

return dictionary.TryGetValue(name, out result);

}

/// <summary>

/// If you try to set a value of a property taht is not defined in the class, this method is called

/// </summary>

/// <param name="binder"></param>

/// <param name="value"></param>

/// <returns></returns>

public override bool TrySetMember(SetMemberBinder binder, object value)

{

dictionary[binder.Name.ToLower()] = value;

return true;

}

/// <summary>

/// Try to set a method not defined in the class, this method is called

/// </summary>

/// <param name="binder"></param>

/// <param name="args"></param>

/// <param name="result"></param>

/// <returns></returns>

public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)

{

dynamic method = dictionary[binder.Name.ToLower()];

result = method(args);

return result != null;

}

}

public void Run()

{

dynamic person = new DynamicPerson();

person.FirstName = "Dynamic";

person.LastName = "Property";

Action<object> action = item => { Console.WriteLine(item.ToString());

dynamic person1 = item; Console.WriteLine(person1.FirstName);

Console.WriteLine(person1.LastName); };

person.Show = action;

person.Show(person);

}

ExpandoObject

ExpandoObject 是一个seadled 类 不实现了IDyanmicMetaObjectProvider 接口,不能从其继承。它的使用方式非常的简单:

public void TestExpandoObject()

{

dynamic expandoObject = new ExpandoObject();

expandoObject.FirstName = "Dynamic";

expandoObject.LastName = "Property";

expandoObject.Show = (Action<object>)(item =>

{

Console.WriteLine("Output dynamic property in dynamic method");

dynamic person1 = item; Console.WriteLine(person1.FirstName);

Console.WriteLine(person1.LastName);

});

expandoObject.Show(expandoObject);

}

如果需要控制动态对象中德属性的添加和访问,则使该对象派生自DynamicObject是最佳的选择。而对于其他情况使用ExpandoObject则比较方便。