天天看點

ExpandoObject, DynamicObject, DynamicMetaObject

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方法中設定斷點,再次運作:

ExpandoObject, DynamicObject, DynamicMetaObject
ExpandoObject, DynamicObject, DynamicMetaObject
ExpandoObject, DynamicObject, DynamicMetaObject

為什麼通路修飾符是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