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();
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的方法-------
//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 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的靜态定義,
案例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
//n1
DynamicMetaObject