ExpandoObject
由于ExpandObject的先天不足(无特征性):
1. ExpandObject不能用于太复杂的对象。
ExpandObject最好还是作为简单的数据容器,不要弄得过于复杂,甚至包含有函数处理。
2.ExpandObject的使用范围必须要短
范围短的意思是,产生和使用ExpandObject的代码的路径必须要短(主要是函数调用路径)。如果你正在使用一个ExpandObject对象,查看产生这个ExpandObject的地方,发现分散在好几个函数之中,还有嵌套的话,那么这个ExpandObject是非常难于维护的。
3. ExpandObject的使用场合最好贴近程序的终端。
比如在MVC中的ViewBag, 就是一个好的例子。ViawBag用于生成页面, 而页面就是MVC程序的终端了。到了终端,ExpandObject也就不能*它人了。
正是由于ExpandObject的无特征性,什么都可以做,所以容易导致滥用。
static void Main(string[] args)
{
Console.WriteLine("-------1.简便存储-------");
{
dynamic expando = new ExpandoObject();
expando.First = "value set dynamically";
expando.Second = 2;
Console.WriteLine(expando.First);
Console.WriteLine(expando.Second);
}
//-------1.简便存储-------
//value set dynamically
//2
Console.WriteLine("-------2.用字典方式存储-------");
{
dynamic expando = new ExpandoObject();
IDictionary<string, object> dictionary = expando;
expando.First = "value set dynamically";
Console.WriteLine(dictionary["First"]);
dictionary["Second"] = "value set with dictionary";
Console.WriteLine(expando.Second);
}
//-------2.用字典方式存储-------
//value set dynamically
//value set with dictionary
Console.WriteLine("-------3.用委托伪造ExpandoObject的方法-------");
{
//Func<int, int> result = x => x + 1;
dynamic expando = new ExpandoObject();
expando.AddOne = (Func<int, int>)(x => x + 1);
Console.Write(expando.AddOne(10));
}
Console.Read();
}
//-------3.用委托伪造ExpandoObject的方法-------
//11
DynamicObject
DynamicObject有个构造函数,但是protected, 也就是我们没有办法直接实例化来使用它。只能是通过继承来构造DynamicObject的对象。
同时DynamicObject中很很多标记为Virtual的方法,比如:
public virtual bool TryGetMember(GetMemberBinder binder, out object result);
public virtual bool TrySetMember(SetMemberBinder binder, object value);
案例1(错误示范):
class DynamicProduct : DynamicObject
{
public string name;
public int Id { get; set; }
public void ShowProduct()
{
Console.WriteLine("Id={0} ,Name={1}", Id, name);
}
#region Override DynamicObject 的方法
public override IEnumerable<string> GetDynamicMemberNames()
{
return base.GetDynamicMemberNames();
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
Console.WriteLine("TryGetMember被调用了,Name:{0}", binder.Name);
return base.TryGetMember(binder, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
Console.WriteLine("TrySetMember被调用了,Name:{0}", binder.Name);
return base.TrySetMember(binder, value);
}
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
{
Console.WriteLine("TryInvoke被调用了");
return base.TryInvoke(binder, args, out result);
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
Console.WriteLine("TryInvokeMember被调用了,Name:{0}", binder.Name);
return base.TryInvokeMember(binder, args, out result);
}
#endregion
}
static void Main(string[] args)
{
dynamic dynProduct = new DynamicProduct();
dynProduct.name = "n1"; //调用TrySetMember方法
dynProduct.Id = 1;
dynProduct.Id = dynProduct.Id + 3;
dynProduct.ShowProduct();
Console.ReadLine();
}
//-------DynamicObject-------
//Id=4 ,Name=n1
//n1
没有执行TryXXX....
将DynamicProduct 中的name修饰符改为private:
private string name;
可以在TrySetMember方法中设置断点,再次运行:
为什么访问修饰符是Public不调用TrySetMember,是Private 就调用了呢??
难道是因为private抛出了异常吗??
再次看看Msdn对此的TrySetMember方法的解释:
Msdn****备注
…………….动态语言运行库 (DLR) 将首先使用语言联编程序在类中查找属性的静态定义。 如果没有此类属性,****DLR 调用 TrySetMember 方法。
问题的原因是这样的:首先DLR 使用语言联编程序在类中查找name的静态定义,
因为name是public,所以查找到了,然后返回,不会去调用TrySetMember方法了,
但是如果name是private,那么联编程序在类中没找到name的静态定义,于是DLR尝试调用TrySetMember方法。
案例2:(正确示范)
public class DynamicProduct : DynamicObject
{
Dictionary<string, Object> _dic = new Dictionary<string, object>();
//设置为 public ,赋值时,就不会访问 TrySetMember
//private object name { get; set; }
//public int Id { get; set; }
//public void ShowProduct()
//{
// Console.WriteLine("Id={0} ,Name={1}", Id, name);
//}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
Console.WriteLine("TryGetMember被调用了,Name:{0}", binder.Name);
var name = binder.Name;
return _dic.TryGetValue(name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
Console.WriteLine("TrySetMember被调用了,Name:{0}", binder.Name);
_dic[binder.Name] = value;
return true;
}
}
static void Main(string[] args)
{
dynamic dynProduct = new DynamicProduct();
dynProduct.name = "n1"; //调用TrySetMember方法
//dynProduct.Id = 1;
//dynProduct.Id = dynProduct.Id + 3;
//dynProduct.ShowProduct();
Console.WriteLine(dynProduct.name);
Console.ReadLine();
}
//output:
//TrySetMember被调用了,Name:name
//TryGetMember被调用了,Name:name
//n1
DynamicMetaObject
未完...
参考:
理解C# 4 dynamic(3) – DynamicObject的使用
浅谈Dynamic 关键字系列之三(下):ExpandoObject,DynamicObject,DynamicMetaObject