自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C#動(dòng)靜結(jié)合編程中的Duck Typing方法

開(kāi)發(fā) 后端
本文作者Todd具備多年.NET編程經(jīng)驗(yàn),今天將講到的是Duck Typing方法。也就是將委托的思想應(yīng)用于對(duì)象,相信這一方法能給大家在實(shí)際開(kāi)發(fā)過(guò)程中帶來(lái)幫助。

引言

C#是靜態(tài)類(lèi)型語(yǔ)言,要使用類(lèi)型必須引用該類(lèi)型的定義。因此,從軟件組織角度會(huì)發(fā)生組件間的引用依賴(lài)關(guān)系。常見(jiàn)的引用依賴(lài)關(guān)系有兩種模式:

a. 正向依賴(lài):組件A用到了組件B中定義的類(lèi)T,組件A直接引用組件B,依賴(lài)關(guān)系是“組件A -> 組件B”。

b. 反向依賴(lài):組件A通過(guò)接口I定義功能規(guī)范,針對(duì)抽象編程;組件B反過(guò)來(lái)引用組件A,并定義類(lèi)T實(shí)現(xiàn)接口I;由另一組件C將I與T粘合起來(lái),依賴(lài)關(guān)系是“組件A <- 組件B”。這就是著名的IoC方式。

簡(jiǎn)單說(shuō)來(lái),IoC是“誰(shuí)制定規(guī)范,誰(shuí)就擁有控制權(quán);誰(shuí)執(zhí)行規(guī)范,誰(shuí)就被控制”。如果規(guī)范借助于C#的靜態(tài)類(lèi)型檢查,比如接口或抽象類(lèi),那么規(guī)范就表現(xiàn)出較強(qiáng)的語(yǔ)法約束性,使得組件A的編寫(xiě)比較獨(dú)立,而組件B則受制與組件A。

本系列的第一篇舉了一個(gè)基于接口的IoC例子,我們看到當(dāng)需要采用第三方組件時(shí),為了適用接口的靜態(tài)類(lèi)型約束,不得不增加一個(gè)adapter去實(shí)現(xiàn)接口并包裝對(duì)第三方組件的調(diào)用。這表現(xiàn)出基于接口的IoC在粘合規(guī)范與實(shí)現(xiàn)時(shí)不太靈活。

但是,規(guī)范和類(lèi)型約束沒(méi)有必然的聯(lián)系。在基于委托的IoC例子中,我們不需要任何的adapter,就能輕松的粘合規(guī)范與實(shí)現(xiàn),表現(xiàn)出較強(qiáng)的靈活性。這就是通過(guò)委托定義規(guī)范,不會(huì)造成組件B對(duì)組件A的依賴(lài),組件A和組件B的實(shí)現(xiàn)都顯得比較獨(dú)立。

實(shí)際上,我們還可以有比委托更靈活的規(guī)范表達(dá)方式,比如:通過(guò)HTTP + XML來(lái)表達(dá)規(guī)范,這樣甚至是語(yǔ)言無(wú)關(guān)的,完全可能組件A由C#編寫(xiě),組件B由Java編寫(xiě)。

上面列舉的3種規(guī)范定義方式:基于接口、基于委托、基于HTTP + XML分別代表了由約束到協(xié)議,由嚴(yán)格到靈活的3種風(fēng)格。當(dāng)然,還有更多的方式,但這里只列舉這三種作為代表。動(dòng)與靜之間需要把握一個(gè)分寸,接口過(guò)于死板;而HTTP + XML的方式則完全是基于運(yùn)行時(shí)協(xié)議的,需要自己做很多檢查工作;委托的好處在于既消除了組件A、B的依賴(lài)關(guān)系,又能享受IDE智能提示和編譯器檢查(簽名檢查)等好處。因此,委托是把動(dòng)與靜結(jié)合得恰到好處的中庸之道。

Duck Typing

但可惜委托還無(wú)法覆蓋接口或類(lèi)的所有功能,有朋友提到“接口是對(duì)象功能的抽象,而委托是方法功能的抽象”就是這個(gè)意思。那么我們自然會(huì)想,有沒(méi)有一種方式,能將委托的思想應(yīng)用于對(duì)象呢?有!它就是:duck typing。前文已經(jīng)談到,duck typing關(guān)注“對(duì)象能做什么”或者說(shuō)“如何使用對(duì)象”,對(duì)象繼承自什么類(lèi),或者實(shí)現(xiàn)什么接口并不重要。duck typing的本意為“如果一只動(dòng)物,走起來(lái)像鴨子,叫起來(lái)像鴨子,我就可以把它當(dāng)作鴨子”。與繼承性多態(tài)相對(duì)應(yīng),duck typing可以實(shí)現(xiàn)非繼承多態(tài)。按duck typing的本意,純正的duck typing看起來(lái)應(yīng)該是這個(gè)樣子:

static void Main(string[] args) 
{
    object person= new Person();
    IPerson duck= Duck.Create(person);//創(chuàng)建鴨子對(duì)象
    Console.WriteLine(duck.Name + " will be " + (duck.Age + 1) + "next year");
    duck.Play("basketball");
    Console.WriteLine(duck.Mother);//為null
    //duck無(wú)法調(diào)用duck.Sing()
}
interface IPerson
{
    string Name { get; }
    int Age { get; }
    string Mother { get; }
    void Play(string ball);
}
class Person
{
    public string Name { get { return "Todd"; } }
    public int Age { get { return 26; } }
    public void Play(string ball) { Console.WriteLine("Play " + ball); }
    public void Sing(string song) { Console.WriteLine("Sing " + song");}
}

上面的例子中,雖然person對(duì)象沒(méi)有實(shí)現(xiàn)IPerson接口,我們一樣可以通過(guò)Duck.Create(person)創(chuàng)建鴨子對(duì)象調(diào)用person的屬性和方法。這種把接口和對(duì)象粘合的方式與委托和方法的粘合方式非常接近,真正達(dá)到了我們所謂把委托思想應(yīng)用于對(duì)象的想法。

C#中要實(shí)現(xiàn)Duck.Create的功能,可以通過(guò)Emit動(dòng)態(tài)創(chuàng)建實(shí)現(xiàn)T接口的代理類(lèi),在代理類(lèi)中攔截方法調(diào)用,并將方法調(diào)用轉(zhuǎn)換成target對(duì)象上的反射調(diào)用。Castle開(kāi)源項(xiàng)目的DynamicProxy是一個(gè)很好用的工具,在它的幫助下很容易實(shí)現(xiàn)代理類(lèi)的創(chuàng)建和方法調(diào)用的攔截。

動(dòng)態(tài)類(lèi)型

事實(shí)上,duck typing是動(dòng)態(tài)類(lèi)型概念的一種。C#4.0已經(jīng)通過(guò)dynamic關(guān)鍵字來(lái)實(shí)現(xiàn)動(dòng)態(tài)類(lèi)型,讓我們先來(lái)看看下面的示例:

string json = @"{ ""FirstName"": ""John"", ""LastName"": ""Smith"", ""Age"": 21 }"; 
dynamic person = CreateFromJson(json);
Console.WriteLine("{0} will be {1} next year", person.FirstName, person.Age + 1);
Console.WriteLine(person.ToJson());
person.Play("basketball");
string firstName = person.FirstName;
int age = person.Age;
Func toJson = person.ToJson>;
Action play = person.Play>;

通過(guò)dynamic關(guān)鍵字,我們不需要在編譯時(shí)為person對(duì)象指定類(lèi)型,編譯器不會(huì)進(jìn)行類(lèi)型檢查,而是將對(duì)象的屬性訪問(wèn)和方法調(diào)用轉(zhuǎn)換為反射調(diào)用,所以,只要對(duì)象的運(yùn)行時(shí)類(lèi)型能通過(guò)反射找到匹配的屬性或方法即可。

上面的例子通過(guò)json創(chuàng)建了一個(gè)dynamic對(duì)象,就像javascript中操作json一樣方便。在運(yùn)行 時(shí),person.FirstName和person.Age能通過(guò)反射正確地進(jìn)行屬性訪問(wèn),person.ToJson()也可以正確地執(zhí)行,但 person.Play( "basketball")由于運(yùn)行時(shí)類(lèi)型不存在該方法而拋出異常。

C#4.0的味道如何?很爽嗎?不過(guò),說(shuō)實(shí)在的,我覺(jué)得有點(diǎn)兒不太舒服了!仔細(xì)想想,它像接口,像委托,還是更像HTTP + XML? 對(duì)于dynamic對(duì)象,編譯器不進(jìn)行對(duì)象類(lèi)型檢查,不進(jìn)行屬性類(lèi)型檢查,也不進(jìn)行方法簽名檢查。很明顯,它像HTTP+XML,完全基于運(yùn)行時(shí)協(xié)議,沒(méi)有一點(diǎn)兒靜態(tài)的東西。如果類(lèi)比委托的話(huà),更理想的方式應(yīng)該是,不進(jìn)行對(duì)象類(lèi)型檢查,但進(jìn)行屬性類(lèi)型和方法簽名檢查,就像下面這樣:

string json = @"{ ""FirstName"": ""John"", ""LastName"": ""Smith"", ""Age"": 21 }";
dynamic person = CreateFromJson(json);
Console.WriteLine("{0} will be {1} next year", person.FirstName, person.Age + 1);
Console.WriteLine(person.ToJson());
person.Play("basketball");//不存在的方法,可以通過(guò)編譯,但會(huì)拋出運(yùn)行時(shí)異常

這樣,除了屬性和方法的名稱(chēng)是動(dòng)態(tài)的外,屬性的類(lèi)型和方法的簽名都是靜態(tài)的,把運(yùn)行時(shí)錯(cuò)誤的可能降到最低,同時(shí)享受靜態(tài)檢查的好處。其實(shí),沿著這個(gè)思路,我們大可不必等著C#4.0的dynamic才開(kāi)始動(dòng)態(tài)類(lèi)型,在C#2.0時(shí)代也可以這樣:

object jsonObj = CreateFromJson(@"{ ""FirstName"": ""John"", 
""LastName"": ""Smith"", ""Age"": 21 }");
Dynamic person = new Dynamic(jsonObject);
string firstName = person.Property("FirstName");
int age = person.Age("Age");
Func toJson = person.Method>("ToJson");
Action play = person.Method>("Play");

看到這里,相信您一定明白該如何實(shí)現(xiàn)Dynamic類(lèi)了吧?如果覺(jué)得有用,就自己嘗試實(shí)現(xiàn)一下吧!

博文鏈接:http://www.cnblogs.com/weidagang2046/archive/2009/03/26/1421943.html

【編輯推薦】

  1. C#實(shí)用基礎(chǔ)教程
  2. 詳解C# 4.0中必選參數(shù)與可選參數(shù)混合的問(wèn)題
  3. 淺析C#3.0編碼習(xí)慣與命名規(guī)則
責(zé)任編輯:彭凡 來(lái)源: 博客園
相關(guān)推薦

2009-03-12 09:05:18

接口C#.NET

2009-02-20 09:50:29

C#方法重載編程

2009-04-10 09:55:44

C#反射.NET

2009-08-03 13:23:04

C#編程組件-事件-委托

2009-01-16 09:58:07

C#編程C#內(nèi)存管理垃圾收集

2024-10-21 16:59:37

C#編程多線程

2009-03-10 13:59:41

C#套接字編程

2009-07-20 09:53:43

Java混合編程

2012-04-28 15:28:21

JNI混合編程Java

2024-11-20 17:28:00

C#CPU代碼

2012-03-20 11:37:24

JavaJNI

2011-07-01 14:55:28

Qt QML C++

2009-08-21 16:35:08

使用C#結(jié)合ADO.N

2009-09-08 16:22:27

c# listBox

2020-02-28 09:00:00

ObjectC#編程語(yǔ)言

2009-08-24 11:02:52

C#接口映射

2009-08-26 10:34:15

C#類(lèi)型C#變量

2009-08-24 09:55:26

C#接口轉(zhuǎn)換

2009-08-21 10:17:14

C#異步網(wǎng)絡(luò)編程

2009-08-12 14:01:17

C# Excel編程技
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)