淺談dynamic的簡單使用用法


今天看了博客園里面的dynamic用法,我猶豫從來沒接觸過,今天惡補了一下,把我對dynamic的認識分享了出來,大家一起學習。

Visual C# 2010 引入了一個新類型 dynamic。

該類型是一種靜態類型,但類型為 dynamic 的對象會跳過靜態類型檢查。

大多數情況下,該對象就像具有類型 object 一樣。 在編譯時,將假定類型化為 dynamic 的元素支持任何操作。

為什么會有這個類呢,我們可以看一下js的代碼來判斷為什么會需要這個類

window.onload = function () {

var person1 = new Object();

 

person1.SayHi= function () { alert("我Sayhi方法"); }

var person2 = new Object();

 

IsMetheod(person1);//我是SayHi方法

IsMetheod(person2);//沒有此方法

}

function IsMetheod(obj)

{

if (obj && typeof obj.SayHi === "function") {

return obj.SayHi();

}

else {

alert("沒有此方法");

return null;

}

}

 

通過js代碼我們可以去直接在對象上添加屬性,而且還可以在使用屬性之前去判斷該屬性或者方法是否存在。如果想要這樣做,我們可以直接去操作dynamic對象去操作。

首先我們應先了解到一個接口,雖然dynamic可以像object類一樣標識大部分類,但是如果想要用到像下面的例子一樣動態的為對象綁定屬性,必須實現IDynamicMetaObjectProvider這個接口。(這個接口我們先看完這個例子再說)

dynamic dy = new ExpandoObject();

dy.name = ".NET";

dy.age = 5;

 

Console.WriteLine(dy.name+":"+dy.age);//".NET:5"

 

大家可能看到了我們new的不是dynamic,對的,應為dynamic是一個靜態的類型,所以我們是沒有辦法去new的,那怎樣得到呢,這就提到了IDynamicMetaObjectProvider這個接口了,至於這個接口有什么用,微軟官網上是這么說的"表示一個動態對象,在運行時可將該對象的操作進行綁定。"這也就是說,我們在程序編譯之后運行的時候,把給對象綁定的方法動態的加載進去,所以,我們為dynamic對象綁定屬性的時候,編譯是能通過的,只是在運行的時候會出錯。

這個接口里面只有一個方法GetMetaObject(),這個方法的作用是返回 DynamicMetaObject,它負責綁定對此對象執行的操作。所以只要實現了這個接口,我們就可以對實現該接口的類執行動態綁定操作。上例中也正是因為ExpanoObject實現了這個接口,可以通過new 這個類來演示動態綁定對象的方法。

但是如果把這些動態綁定的屬性直接加在了dynamic上面,肯定不合適。這就需要將這個功能給擴展出來,剛才提到了,只要實現了那個接口就可以實現數據的動態綁定,可能不是很准確。在實際中也不會說只會去實現那個接口就能完成屬性的動態添加。幸運的是.c#已經給出了一個接口去供我們繼承,只要我們使用的類繼承了DynamicObject這個類,我們可以通過重寫里面的一些方法來擴展屬性。下圖是C#定義的DynamicObject

 

好了,說了這么多鋪墊,我們來真正看一下比較簡單的應用吧,我們以前寫c#代碼是不能通過js去那樣寫的的,讓我們來看看通過dynamic我們是否可以完成這樣的寫法呢?

注意:下面的方法都是DynamicObject定義的,我們重寫就好了,不必糾結為什么這樣,看完再說。

 

public class Mydynamic:DynamicObject

{

//轉杯一個數據字典,去保存我們屬性和屬性值

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

 

public override IEnumerable<string> GetDynamicMemberNames()

{

return dic.Keys;

}

//設置值的屬性

public override bool TrySetMember(SetMemberBinder binder, object value)

{

dic[binder.Name] = value;

return true;

}

 

//得到值

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

{

 

dic.TryGetValue(binder.Name,out result);

return true;

}

 

class Program

{

static void Main(string[] args)

{

dynamic dy = new Mydynamic();

dy.Name = "小白";

dy.age = 15;

Console.WriteLine(dy.Name+":"+dy.age);//"小白:15"

Console.ReadKey();

}

}

 

看到了吧,我們通過繼承的DynamicObject這個類同樣可以實現對對象屬性的動態添加,不過要注意這里面的兩個方法,就是TryGetMenber和TryGetMember這兩個方法,沒錯這兩個方法就是為為動態屬性賦值和取值的,此外還有很多刪除、通過下標得到屬性等方法。設置值和取值的方法給我們了,我們如果想對獲取的值進行業務的處理,在這里完全可以做得到。我們還是來現分析一下,這個主程序是怎么工作的,當dy.Name的時候,先從該類的集合字典里面去找,如果找到這個屬性,為其賦值或者修改,如果沒有找到,則添加到數據字典里。在運行的時候,綁定到這個對象上,該對象就有了該屬性了。

我們再看一下一個判斷業務的例子吧,

假定您需要一種數據結構來存儲數字的文本和數值表達式,並且您希望定義此數據結構到字符串和整數的轉換。

下面的代碼示例演示如何實現從 DynamicObject 類派生的 DynamicNumber 類。 DynamicNumber 重寫 TryConvert 方法來啟用類型轉換。 它還會覆蓋 TrySetMember 和TryGetMember 方法以允許訪問數據元素。

在此示例中,僅支持到字符串和整數的轉換。 如果試圖將對象轉換為任何其他類型,將引發運行時異常。

 

 

public class Demo_dynymic:System.Dynamic.DynamicObject

{

 

Dictionary<string, object> dictionary

= new Dictionary<string, object>();

 

 

public override bool TryGetMember(

GetMemberBinder binder, out object result)

{

return dictionary.TryGetValue(binder.Name, out result);

}

 

 

public override bool TrySetMember(

SetMemberBinder binder, object value)

{

dictionary[binder.Name] = value;

return true;

}

//這個方法是用類型轉換的。

public override bool TryConvert(

ConvertBinder binder, out object result)

{

if (binder.Type == typeof(String))

{

result = dictionary["Txt"];

return true;

}

if (binder.Type == typeof(int))

{

result = dictionary["Num"];

return true;

}

return base.TryConvert(binder, out result);

}

}

 

 

 

class Program

{

static void Main(string[] args)

{

dynamic dy = new Demo_dynymic();

dy.Txt = "哈哈哈";

dy.Num = 1;

int num = dy;//會啟用TryConvert

string txt = dy;//會啟用TryConvert

Console.WriteLine(num+txt);//1哈哈哈

Console.ReadKey();

}

}

 

我們再來看看里面的TryInvoke這個方法的用法吧。

TryInvoke從 DynamicObject 類派生的類可以重寫此方法,以指定如何為動態對象執行調用對象的操作。 未重寫此方法時,語言的運行時聯編程序確定該行為。(大多數情況下,將引發運行時異常。)

如果此方法被重寫,當您執行運算(如 sampleObject(100))時自動調用此方法,其中 sampleObject 從 DynamicObject 類派生。說簡單點,就是我們可以通過重寫這個方法,使用函數的形式來改變類對象的行為,也就是說我們通過函數形式來操作該類的屬性。舉個例子。

我們不想通過類名.屬性的方式來添加屬性,我們可以改寫TryInvoke方法來完成通過函數參數形式賦值。具體看代碼。

public override bool TryInvoke(

InvokeBinder binder, object[] args, out object result)

{

//有兩個參數,而且第一個參數是整型,第二個是字符型。

//因為我們通過這種形式賦值,所以在用的時候,數據類型一定要一致。

if ((args.Length == 2) &&

(args[0].GetType() == typeof(int)) &&

(args[1].GetType() == typeof(String)))

{

if (dictionary.ContainsKey("Num"))

dictionary["Num"] = args[0];

else

dictionary.Add("Num", args[0]);

if (dictionary.ContainsKey("Txt"))

dictionary["Txt"] = args[1];

else

dictionary.Add("Txt", args[1]);

 

result = true;

return true;

}

else

{

result = false;

return false;

}

}

class Program

{

static void Main(string[] args)

{

dynamic dy = new Demo_dynymic();

//通過方法對屬性賦值

dy(1, "one");

//因為屬性名在后台我們已經確定了,所以訪問的時候要寫出來

//注意:.不出來,因為編譯的時候,屬性還不存在,只有運行的時候,才存在

Console.WriteLine(dy.Txt+dy.Num);//one1

Console.ReadKey();

}

}

 

還有很多方法,我就不一一例舉了,總之要實現對對象的動態屬性添加,有幾個步驟

 1. 子類里面包含一個私有變量,用於存儲數據. 這暫且叫做Data;

 2.TryGetMember(GetMemberBinder binder, out object result) 方法實現對數據的獲取. binder.Name就是需要獲取的屬性的名稱,result 是獲取的屬性值. 通過binder.Name在Data中獲取到對應的屬性值,傳出到外面.(注意到了吧result是out參數)

3.TrySetMember(SetMemberBinder binder, object value) 對存在的屬性進行賦值. 上面的Set方法中,我都判斷了binder.Name在data里面是否存在。如果不存在就無法賦值。返回false,如果外面對不存在的屬性復制那么將會報錯.。

參考:http://www.cnblogs.com/FourLeafCloverZc/p/4348722.html

https://msdn.microsoft.com/zh-cn/library/system.dynamic.dynamicobject(v=vs.110).aspx


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM