C 4 0和VS2010新特性(三)

2021-09-30 10:22:29 字數 4918 閱讀 2549

vs2010之所以那麼強大,究其原因是其背後有著強大的c#4.0作為後台支撐。和以往的所有版本相比,c#4.0的動態性大大增強——dynamic就是乙個非常明顯的例子:

(一)dynamic初探:

以前因為某些特殊原因,需要動態的呼叫外部類(假設這個類是實現了某個帶有引數的介面函式的),通常我們只能用反**。示例**如下:

assembly asm = assembly.loadfile(「***xx」)

asm.createinstance("myassembly.classname").gettype().invokemember("say", bindingflags.invokemethod, null, asm.createinstance("myassembly.classname "), new string );

這裡順便簡略說一下反射流程:首先通過絕對路徑載入某個net的dll檔案,然後建立該assembly中某個class的instance(該class必須有無參建構函式),獲取其型別之後動態呼叫其函式say,「bindingflags.invokemethod」表明是乙個普通類方法,「null」的地方是傳遞乙個引數名的,和指明最後的string中的一串values內容一一匹配的……可見使用反射呼叫函式是很痛苦的一件事情。

現在呢?您根本不需要那麼麻煩了!因為c#的dynamic會為您做好一切的,下面就是見證奇蹟的時刻——

assembly asm = assembly.loadfile("***xx");

dynamic dfun = asm.createinstance("myassembly.classname");

dfun.say("hello!");

注意到咖啡色的**了麼——什麼?dynamic竟然可以智慧型感知出動態載入的那個類的方法say?其實不然:當你按下這個點的時候,ide是沒有智慧型感知的,但是如果你知道這個類是有這個方法(因為介面給了其乙個契約,必須實現介面中的方法;而介面的方法是公開的),你就可以完全不理會智慧型感知,照樣寫,照樣編譯通過執行。神奇吧!

看到這裡,你就不會認為dynamic和var是「差不多」的概念了(var無非是根據賦值的型別編譯器自己判斷;且var不能作為函式返回值型別,但是dynamic可以)。

或許有人會疑問:dynamic可以完全替代類似像簡單工廠、抽象工廠一類的東西了咯?我的理解是——不對!從上面的定義中可以得知:dynamic必須首先獲取物件例項,然後動態反射是它做的事情;如果完全取代反射,例項也獲取不到,如何反射呢?真是「巧婦難為無公尺之炊」啊!

說道dynamic可以作為返回值,下面給出乙個例子:

class dynamicclass

public int num2

public dynamicclass(int n1, int n2)

public dynamic dynamicaction

}

主函式注意咖啡色部分:

static void main(string args)

道理很簡單:因為dynamic型別可以賦值任何東西(包括匿名委託),所以我建立了乙個匿名委託給它。然後呼叫計算結果(匿名委託的呼叫使用invoke,可以省略)。

但是……dynamic不僅僅可以動態反射類方法和屬性,還可以「空中樓閣」般動態地去建立乙個類方法和屬性,並且賦值,相信嗎?這是第二話。

(二)神奇的expandoobject類和自定義動態類擴充套件:

dynamic在第一話中已經展示它動態根據賦值型別直接自動完成反射的強大功能。現在又是乙個新奇蹟的誕生——

static void main(string args)

初看這個**只是簡單的讀寫name屬性,毫無稀奇可言。但是你注意哦——你到msdn——或者你索性new expandoobject().name 試試看,有name和action這個屬性嗎?——沒有啊,真的沒有!嘿,奇了怪了,既然沒有,為什麼你可以憑空「捏造出乙個屬性」,而且可以給屬性賦值,並且讀取屬性內容呢?

俗話說的好——天下沒有白給的食——微軟這個類意在向我們揭露乙個驚天的大秘密,那就是你可以自定義dynamic類,讓這個類跟隨你的要求動態的改變自己(比如增加乙個新屬性等)。我們可以參照msdn,給出乙個自定義的expandoobject:

public class ******dynamic : dynamicobject

if (args != null)

stringbuilder sbu = new stringbuilder();

foreach (var item in args)

result = sbu.tostring();

return true;

} public override bool trysetmember(setmemberbinder binder, object value)

return true; }

public override bool trygetmember(getmemberbinder binder, out object result)

} 首先說明這個例子的作用:隨意增加不重複的屬性並賦值(取值),並且讓你隨意建立或者呼叫(帶參或無參)函式進行輸入(輸出)。

分析一下這個類的主要特點:

一般地,任何乙個類——如果需要動態為自身新增屬性、方法等的,就必須實現idynamicobjectprovidor介面或者是dynamicobject虛類(之所以用虛類的原因是「各取所需」的緣故,dynamicobject類都通過虛方法virtual去「實現」了介面中所有的方法,只要繼承了這個類,讀者可以根據需要「任意」動態覆蓋你要的方法)。這裡介紹三個最常見的方法:

o          如果需要支援動態建立寫屬性,必須覆蓋trysetmember,其方法介紹如下:

引數名稱

作用說明

binder:setmemberbinder型別

用於獲取動態建立賦值屬性的時候「屬性名」等一些常見資訊(如示例中name獲取動態賦值的那個屬性)。

value:object型別

用於獲取設定動態屬性的那個值。

o          如果需要支援動態建立讀屬性,必須覆蓋trygetmember,其引數作用和trysetmember大致相當,只是反作用(用於獲取某個已有屬性的內容,並且反向傳遞給object作為輸出結果,注意trygetmember的value是乙個out型別)。同時,這個函式多出乙個result型別,用於返回已有屬性的儲存的值(null丟擲異常,被認為是錯誤的)。

o          如果需要動態呼叫函式並輸出結果,必須覆蓋tryinvokemember方法,此函式比較複雜:

引數名稱

作用說明

binder:invokememberbinder型別

(比如name是函式名,其中還有乙個callinfo內嵌屬性,您還可以獲得argumentnames(c#4.0中最新的可選引數的名稱,通過其argumentnamecount獲取可選引數名的總個數))。

args:object型別

獲取動態給函式賦的值。

result:object型別

返回動態函式執行的結果,null表示異常。

根據以上**,對照不難讀懂我的示例**——現在假設你是這樣呼叫的: 1)

dynamic d = new ******dynamic();

d.name = 「serviceboy」;

console.writeline(d.name);

首先建立了乙個d的動態型別,然後當賦值給name的時候,因為name是屬性,所以觸發了「trysetmember」函式,該函式自動檢查是否已經存在這個屬性名,如果不存在,則將其新增進入乙個dictionary中並將對應賦予的值傳遞進去儲存起來。當使用輸出的時候,同樣地,trygetmember被觸發,系統檢測是否預先建立過這個值,如果沒有,則丟擲異常;存在的話,取出對應的儲存value並返回給系統。 2)

dynamic d = new ******dynamic();

console.writeline(d.say(「hello!」));

首先建立了乙個d的動態型別,當動態建立乙個方法的時候,系統檢測是否包含這個方法名,不包含將新增這個方法名到dictionary儲存,接著檢查引數是否為空,不為空把引數賦值給那個函式名作為key的dictionary中儲存,最後使用stringbuilder串起來賦值給result作為輸出。

下面給出乙個比較複雜的例子——自定義的xml建立器(仿jeffery zhao):

public class xmlcreator : dynamicobject

result = root;

} //否則是子節點

else

//拷貝所有屬性值到陣列:

string values = new string[args.length - 1];

for (int i = 1; i < args.length; ++i)

xelement subelement = new xelement(args[0].tostring());

//屬性名稱獲取

for (int i = 0; i < attributes.length; ++i)

result = subelement; }

return result != null; }

}該函式功能是:輸出任意同時帶有屬性的節點,同時可以巢狀——比如:

dynamic xmlcreator = new  xmlcreator();

xelement ele = xmlcreator.createelement(「books」,

xmlcreator(「book」,name:c#,price:100.50) );

大家可以自己想一想是怎麼乙個原理哦。

C 4 0和VS2010新特性

dynamic初探 以前因為某些特殊原因,需要動態的呼叫外部類 假設這個類是實現了某個帶有引數的介面函式的 通常我們只能用反 示例 如下 assembly asm assembly.loadfile xx asm.createinstance myassembly.classname gettype...

C 4 0和VS2010新特性(二)

6 協變和反變 co variant crop variant 這是vs2010新增的乙個內容,用於在編譯的時候確認是否允許不同型別的泛型介面之間是否存在轉換的問題。為了了解 協變 和 反變 的概念,我們先看乙個例子 假設我們定義了乙個介面和若干類 class father public virtu...

vs2010與C 4 0新特性

vs2010被認為將是續寫visual studio 6 的扛鼎之作。整個ide不僅是使用了wpf重構,而且使用了最新的net framework 4作為強大的後援支撐。從上至下可圈可點。下面我們就來看一看vs2010在哪些方面引人注目 1 wpf重構介面 整個vs2010 ide全部使用wpf重構...