由于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(); IDictionarydictionary = 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的方法-------"); { //Funcresult = x => x + 1; dynamic expando = new ExpandoObject(); expando.AddOne = (Func)(x => x + 1); Console.Write(expando.AddOne(10)); } Console.Read(); } //-------3.用委托伪造ExpandoObject的方法------- //11DynamicObject
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 IEnumerableGetDynamicMemberNames() { 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_dic = new Dictionary(); //设置为 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 //n1DynamicMetaObject
未完...