日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > C# >内容正文

C#

深入理解C# 3.x的新特性(2):Extension Method[下篇]

發(fā)布時(shí)間:2024/7/19 C# 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解C# 3.x的新特性(2):Extension Method[下篇] 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

四、Extension Method的本質(zhì)

通過(guò)上面一節(jié)的介紹,我們知道了在C#中如何去定義一個(gè)Extension Method:它是定義在一個(gè)Static class中的、第一個(gè)Parameter標(biāo)記為this關(guān)鍵字的Static Method。在這一節(jié)中,我們來(lái)進(jìn)一步認(rèn)識(shí)Extension Method。

和C# 3.0的其他新特性相似,Extension Method僅僅是C#這種.NET Programming Language的新特性而已。我們知道,C#是一種典型的編譯型的語(yǔ)言,我們編寫的Source Code必須先經(jīng)過(guò)和C# Compiler編譯成Assembly,才能被CLR加載,被JIT 編譯成Machine Instruction并最終被執(zhí)行。C# 3.0的這些新的特性大都影響Source被C# Compiler編譯成Assembly這個(gè)階段,換句話說(shuō),這些新特僅僅是Compiler的新特性而已。通過(guò)對(duì)Compiler進(jìn)行修正,促使他將C# 3.0引入的新的語(yǔ)法編譯成相對(duì)應(yīng)的IL Code,從本質(zhì)上看,這些IL Code 和原來(lái)的IL并沒(méi)有本質(zhì)的區(qū)別。所有當(dāng)被編譯生成成Assembly被CLR加載、執(zhí)行的時(shí)候,CLR是意識(shí)不到這些新的特性的。

從Extension Method的定義我們可看出,Extension Method本質(zhì)上是一個(gè)Static Method。但是我們往往以Instance Method的方式進(jìn)行調(diào)用。C# Compiler的作用很明顯:把一個(gè)以Instance Method方式調(diào)用的Source Code編譯成的于對(duì)應(yīng)于傳統(tǒng)的Static Method調(diào)用的IL Code

雖然Extension Method本質(zhì)上僅僅是一個(gè)Static Class的Static Method成員,但是畢竟和傳統(tǒng)的Static Method有所不同:在第一個(gè)Parameter前加了一個(gè)this關(guān)鍵字。我們現(xiàn)在來(lái)看看他們之間的細(xì)微的差異。我們先定義一個(gè)一般的Static Method:

public?static?Vector?Adds(Vector?v,?Vector?v1)
{
??
return?new?Vector?{?X?=?v.X?+?v1.X,?Y?=?v.Y?+?v1.Y?};
}

注:Vector的定義參見(jiàn)《深入理解C# 3.0的新特性(2):Extension Method - Part I》。

我們來(lái)看看通過(guò)Compiler進(jìn)行編譯生成的IL:

.method?private?hidebysig?static?void??Main(string[]?args)?cil?managed
{
??.entrypoint
??
//?Code?size???????50?(0x32)
??.maxstack??2
??.locals?init?([
0]?class?Artech.ExtensionMethod.Vector?v,
???????????[
1]?class?Artech.ExtensionMethod.Vector?'<>g__initLocal0')
??IL_0000:??nop
??IL_0001:??newobj?????instance?
void?Artech.ExtensionMethod.Vector::.ctor()
??IL_0006:??stloc.
1
??IL_0007:??ldloc.
1
??IL_0008:??ldc.r8?????
1.
??IL_0011:??callvirt???instance?
void?Artech.ExtensionMethod.Vector::set_X(float64)
??IL_0016:??nop
??IL_0017:??ldloc.
1
??IL_0018:??ldc.r8?????
2.
??IL_0021:??callvirt???instance?
void?Artech.ExtensionMethod.Vector::set_Y(float64)
??IL_0026:??nop
??IL_0027:??ldloc.
1
??IL_0028:??stloc.
0
??IL_0029:??ldloc.
0
??IL_002a:??ldloc.
0
??IL_002b:??call???????
class?Artech.ExtensionMethod.Vector?Artech.ExtensionMethod.Extension::Adds(class?Artech.ExtensionMethod.Vector,
class?Artech.ExtensionMethod.Vector)
??IL_0030:??stloc.
0
??IL_0031:??ret
}?
//?end?of?method?Program::Main

對(duì)了解IL的人來(lái)說(shuō),對(duì)上面的IL code應(yīng)該很容易理解。

我們?cè)賮?lái)看看對(duì)于通過(guò)下面的方式定義的Extension Method:

public?static?class?Extension
????
{
?????????
public?static?Vector?Adds(this?Vector?v,?Vector?v1)
????????
{
????????????
return?new?Vector?{?X?=?v.X?+?v1.X,?Y?=?v.Y?+?v1.Y?};
????????}

}

對(duì)于得IL如下:

.method?public?hidebysig?static?class?Artech.ExtensionMethod.Vector?
Adds(
class?Artech.ExtensionMethod.Vector?v,
class?Artech.ExtensionMethod.Vector?v1)?cil?managed
{
??.custom?instance?
void?[System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor()?=?(?01?00?00?00?)?
??
//?Code?size???????53?(0x35)
??.maxstack??3
??.locals?init?([
0]?class?Artech.ExtensionMethod.Vector?'<>g__initLocal0',
???????????[
1]?class?Artech.ExtensionMethod.Vector?CS$1$0000)
??IL_0000:??nop
??IL_0001:??newobj?????instance?
void?Artech.ExtensionMethod.Vector::.ctor()
??IL_0006:??stloc.
0
??IL_0007:??ldloc.
0
??IL_0008:??ldarg.
0
??IL_0009:??callvirt???instance?float64?Artech.ExtensionMethod.Vector::get_X()
??IL_000e:??ldarg.
1
??IL_000f:??callvirt???instance?float64?Artech.ExtensionMethod.Vector::get_X()
??IL_0014:??add
??IL_0015:??callvirt???instance?
void?Artech.ExtensionMethod.Vector::set_X(float64)
??IL_001a:??nop
??IL_001b:??ldloc.
0
??IL_001c:??ldarg.
0
??IL_001d:??callvirt???instance?float64?Artech.ExtensionMethod.Vector::get_Y()
??IL_0022:??ldarg.
1
??IL_0023:??callvirt???instance?float64?Artech.ExtensionMethod.Vector::get_Y()
??IL_0028:??add
??IL_0029:??callvirt???instance?
void?Artech.ExtensionMethod.Vector::set_Y(float64)
??IL_002e:??nop
??IL_002f:??ldloc.
0
??IL_0030:??stloc.
1
??IL_0031:??br.s???????IL_0033
??IL_0033:??ldloc.
1
??IL_0034:??ret
}
?//?end?of?method?Extension::Adds

通過(guò)比較,我們發(fā)現(xiàn)和上面定義的一般的Static Method生成的IL唯一的區(qū)別就是:在Adds方法定義最開(kāi)始添加了下面一段代碼:

.custom?instance?void?[System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor()?=?(?01?00?00?00?)?

這段添加的IL代碼很明顯,就是在Adds方法上添加一個(gè)Customer Attribute:System.Runtime.CompilerServices.ExtensionAttribute。ExtensionAttribute具有如下的定義:

[AttributeUsage(AttributeTargets.Method?|?AttributeTargets.Class?|?AttributeTargets.Assembly)]
public?sealed?class?ExtensionAttribute?:?Attribute
{
}

所以下面Extension Method的定義

public?static?Vector?Adds(this?Vector?v,?Vector?v1)
{
????????????
return?new?Vector?{?X?=?v.X?+?v1.X,?Y?=?v.Y?+?v1.Y?};
}

和下面的定義是等效的

[ExtensionAttribute]
public?static?Vector?Adds(Vector?v,?Vector?v1)?
{
????????????
return?new?Vector?{?X?=?v.X?+?v1.X,?Y?=?v.Y?+?v1.Y?};
}

但是,System.Runtime.CompilerServices.ExtensionAttribute和其他Custom Attribute不一樣,因?yàn)樗菫榱薊xtension Method的而定義的,我們只能通過(guò)添加this Key word的語(yǔ)法來(lái)定義Extension Method。所以當(dāng)我們將System.Runtime.CompilerServices.ExtensionAttribute直接運(yùn)用到Adds方法會(huì)出現(xiàn)下面的Compile Error:

Do?not?use?'System.Runtime.CompilerServices.ExtensionAttribute'.?Use?the?'this'?keyword?instead.

上面我們比較了Extension Method本身IL和一般Static Method IL,現(xiàn)在我們看看當(dāng)我們以Instance Method方式調(diào)用Extension Method的IL。假設(shè)我們通過(guò)下面的方式調(diào)用Adds。 

class?Program
????
{
????????
static?void?Main(string[]?args)
????????
{
?var?v?
=?new?Vector?{?X?=?1,?Y?=?2?};
???????????v?
=?v.Adds(v);
????????}

}

下面是Main Method的IL:

.method?private?hidebysig?static?void??Main(string[]?args)?cil?managed
{
??.entrypoint
??
//?Code?size???????50?(0x32)
??.maxstack??2
??.locals?init?([
0]?class?Artech.ExtensionMethod.Vector?v,
???????????[
1]?class?Artech.ExtensionMethod.Vector?'<>g__initLocal0')
??IL_0000:??nop
??IL_0001:??newobj?????instance?
void?Artech.ExtensionMethod.Vector::.ctor()
??IL_0006:??stloc.
1
??IL_0007:??ldloc.
1
??IL_0008:??ldc.r8?????
1.
??IL_0011:??callvirt???instance?
void?Artech.ExtensionMethod.Vector::set_X(float64)
??IL_0016:??nop
??IL_0017:??ldloc.
1
??IL_0018:??ldc.r8?????
2.
??IL_0021:??callvirt???instance?
void?Artech.ExtensionMethod.Vector::set_Y(float64)
??IL_0026:??nop
??IL_0027:??ldloc.
1
??IL_0028:??stloc.
0
??IL_0029:??ldloc.
0
??IL_002a:??ldloc.
0
??IL_002b:??call???????
class?Artech.ExtensionMethod.Vector?Artech.ExtensionMethod.Extension::Adds(class?Artech.ExtensionMethod.Vector,
class?Artech.ExtensionMethod.Vector)
??IL_0030:??stloc.
0
??IL_0031:??ret
}
?//?end?of?method?Program::Main

通過(guò)上面的IL,我們看到調(diào)用的是Artech.ExtensionMethod.Extension的Adds方法。

IL_002b:??call?class?Artech.ExtensionMethod.Vector?Artech.ExtensionMethod.Extension::Adds(class?Artech.ExtensionMethod.Vector,
class?Artech.ExtensionMethod.Vector)

通過(guò)對(duì)IL的分析,我們基本上看出了Extension Method的本質(zhì)。我們?cè)賮?lái)簡(jiǎn)單描述一下對(duì)Compiler的編譯過(guò)程:當(dāng)Compiler對(duì)Adds方法的調(diào)用進(jìn)行編譯的過(guò)程的時(shí)候,它必須判斷這個(gè)Adds方式是Vector Type的成員還是以Extension Method的方式定義。Extension Method的優(yōu)先級(jí)是最低的,只有確定Vector中沒(méi)有定義相應(yīng)的Adds方法的時(shí)候,Compiler才會(huì)在引用的Namespace中查看這些Namespace中是否定義有對(duì)應(yīng)的Adds Extension Method的Static Class。找到后作進(jìn)行相應(yīng)的編譯,否則出現(xiàn)編譯錯(cuò)誤。

五、一個(gè)完整的Extension Method的Sample

在介紹了Extension Method的本質(zhì)之后,我們通過(guò)一個(gè)相對(duì)完整的Sample進(jìn)一步了解Extension Method的運(yùn)用,通過(guò)這個(gè)Sample,我們還可以粗略了解LINQ的原理。

C# 3.0為L(zhǎng)INQ定義了一系列的Operator:select, from,where,orderby..., 促使我們按照OO的方式來(lái)處理各種各樣的數(shù)據(jù),比如XML,Relational DB Data,C#中IEnumeratable<T> Object。比如:

var?names?=?new?List<string>?{?"Tom?Cruise",?"Tom?Hanks",?"Al?Pacino",?"Harrison?Ford"?};
var?result?
=?names.Where(name?=>?name.StartsWith("Tom"));
foreach(var?name?in?result)
{
??????Console.WriteLine(name);
}

我們通過(guò)上面的Code,從一系列的姓名列表中("Tom Cruise", "Tom Hanks", "Al Pacino", "Harrison Ford")篩選名字(First Name)為Tom的姓名。通過(guò)Where Operator,傳入一個(gè)以Lambda Expression表示的篩選條件(name => name.StartsWith("Tom"))。Where Operator就是通過(guò)Extension Method的方式定義的。

在這里提供的Sample就是定義一個(gè)完成Where Operator相同功能的Operator,我們把這個(gè)Operator起名為When

using?System;
using?System.Collections.Generic;
using?System.Linq;
using?System.Text;
using?System.Collections;

namespace?Artech.ExtensionMethod
{
????
public?delegate?TResult?Function<Tparam,?TResult>(Tparam?param);

????
public?static?class?Extension
????
{
????????
public?static?IEnumerable<TSource>?When<TSource>(this?IEnumerable<TSource>?source,?Function<TSource,?bool>?predicate)
????????
{
????????????
return?new?WhenEnumerator<TSource>(source,?predicate);
????????}
??

????}


????
public?class?WhenEnumerator<TSource>?:?IEnumerable<TSource>,?IEnumerator<TSource>
????
{
????????
private?IEnumerable<TSource>?_source;
????????
private?Function<TSource,?bool>?_predicate;
????????
private?IEnumerator<TSource>?_sourceEnumerator;

????????
public?WhenEnumerator(IEnumerable<TSource>?source,?Function<TSource,?bool>?predicate)
????????
{
????????????
this._source?=?source;
????????????
this._predicate?=?predicate;
????????????
this._sourceEnumerator?=?this._source.GetEnumerator();
????????}


????????
IEnumerable?Members#region?IEnumerable<TSource>?Members

????????
public?IEnumerator<TSource>?GetEnumerator()
????????
{
????????????
return?new?WhenEnumerator<TSource>(this._source,?this._predicate);
????????}


????????
#endregion


????????
IEnumerable?Members#region?IEnumerable?Members

????????IEnumerator?IEnumerable.GetEnumerator()
????????
{
????????????
throw?new?Exception("The?method?or?operation?is?not?implemented.");
????????}


????????
#endregion


????????
IEnumerator?Members#region?IEnumerator<TSource>?Members

????????
public?TSource?Current
????????
{
????????????
get?{?return?this._sourceEnumerator.Current;?}
????????}


????????
#endregion


????????
IDisposable?Members#region?IDisposable?Members

????????
public?void?Dispose()
????????
{
????????????
//throw?new?Exception("The?method?or?operation?is?not?implemented.");
????????}


????????
#endregion


????????
IEnumerator?Members#region?IEnumerator?Members

????????
object?IEnumerator.Current
????????
{
????????????
get
????????????
{
????????????????
return?this._sourceEnumerator.Current;
????????????}

????????}


????????
public?bool?MoveNext()
????????
{
????????????
if?(!this._sourceEnumerator.MoveNext())
????????????
{
????????????????
return?false;
????????????}


????????????
while?(!this._predicate(this._sourceEnumerator.Current))
????????????
{
????????????????
if?(!this._sourceEnumerator.MoveNext())
????????????????
{
????????????????????
return?false;
????????????????}

????????????}


????????????
return?true;
????????}


????????
public?void?Reset()
????????
{
????????????
this._sourceEnumerator.Reset();
????????}


????????
#endregion

????}

}

我們來(lái)看看我們新的LINQ Operator:When的定義。我首先定義了一個(gè)Generic Delegate:Function。實(shí)際上他定義了一個(gè)一元函數(shù)y?=?f(x),TParam和TResult為參數(shù)和返回值得類型。?

public?delegate?TResult?Function<Tparam,?TResult>(Tparam?param);

接著在Static Class Extesnion中定義了Extension Method:When。該方法包含兩個(gè)參數(shù),其中一個(gè)是執(zhí)行篩選的數(shù)據(jù)源,另一個(gè)是用于判斷數(shù)據(jù)源每個(gè)對(duì)象是否滿足你所定義的篩選條件的斷言。返回一個(gè)我們自定義的、實(shí)現(xiàn)了IEnumerable的WhenEnumerator對(duì)象。

public?static?class?Extension
????
{
????????
public?static?IEnumerable<TSource>?When<TSource>(this?IEnumerable<TSource>?source,?Function<TSource,?bool>?predicate)
????????
{
????????????
return?new?WhenEnumerator<TSource>(source,?predicate);
????????}
?
????}

WhenEnumerator的定義是實(shí)現(xiàn)When Extension Method的關(guān)鍵,我們現(xiàn)在著重來(lái)介紹它的具體實(shí)現(xiàn)。WhenEnumerator實(shí)現(xiàn)了Interface Enumerable<T>,為了簡(jiǎn)單,我們也它對(duì)應(yīng)的Enumerator的實(shí)現(xiàn)也定義在同一個(gè)Class中,所以WhenEnumerator實(shí)現(xiàn)了兩個(gè)Interface:IEnumerable<TSource>, IEnumerator<TSource>。?

以下3個(gè)成員分別代表:用于執(zhí)行篩選的數(shù)據(jù)源、用于判斷是否滿足篩選條件的斷言以及數(shù)據(jù)源的Enumerator對(duì)象。

private?IEnumerable<TSource>?_source;
private?Function<TSource,?bool>?_predicate;
private?IEnumerator<TSource>?_sourceEnumerator;

通過(guò)返回一個(gè)WhenEnumerator對(duì)象,實(shí)現(xiàn)了IEnumerable<TSource>的GetEnumerator()方法。?

????????public?IEnumerator<TSource>?GetEnumerator()
????????
{
????????????
return?new?WhenEnumerator<TSource>(this._source,?this._predicate);
????????}

對(duì)于另一個(gè)Interface IEnumerator<TSource>,直接調(diào)用數(shù)據(jù)源的Enumerator的同名方法實(shí)現(xiàn)了Current,和Reset()。對(duì)于MoveNext()則通過(guò)如下的方式實(shí)現(xiàn):把當(dāng)前的位置設(shè)置在下一個(gè)滿足篩選條件的Element上

public?bool?MoveNext()
????????
{
????????????
if?(!this._sourceEnumerator.MoveNext())
????????????
{
????????????????
return?false;
????????????}


????????????
while?(!this._predicate(this._sourceEnumerator.Current))
????????????
{
????????????????
if?(!this._sourceEnumerator.MoveNext())
????????????????
{
????????????????????
return?false;
????????????????}

????????????}


????????????
return?true;
????????}

到現(xiàn)在為止,這個(gè)新的LINQ Operator被創(chuàng)建,現(xiàn)在我們可以按照使用Where operator的方式來(lái)調(diào)用When。

我們可以通過(guò)Delegate的方式來(lái)使用When Operator:

class?Program
????
{
????????
static?void?Main()
????????
{
????????????var?names?
=?new?List<string>?{?"Tom?Cruise",?"Tom?Hanks",?"Al?Pacino",?"Harrison?Ford"?};
????????????var?result?
=?names.When(delegate(string?name)?{?return?name.StartsWith("Tom");?});
????????????
foreach?(var?name?in?result)
????????????
{
????????????????Console.WriteLine(name);
????????????}

????????}

}

輸出結(jié)果:

Tom?Cruise
Tom?Hanks

我們也可以通過(guò)Lambda Expression的方式來(lái)使用When Operator:

static?void?Main()
????????
{
????????????var?names?
=?new?List<string>?{?"Tom?Cruise",?"Tom?Hanks",?"Al?Pacino",?"Harrison?Ford"?};
????????????var?result?
=?names.When(name=>name.StartsWith("Tom"));
????????????
foreach?(var?name?in?result)
????????????
{
????????????????Console.WriteLine(name);
????????????}

????????}

顯然這種方式更簡(jiǎn)潔。?

Deferred Evaluation

對(duì)于LINQ,有一個(gè)非常重要的特征:Deferred Evaluation。在了解這個(gè)特征之前,我們來(lái)看一個(gè)例子:

static?void?Main()
{
????????????var?names?
=?new?List<string>?{?"Tom?Cruise",?"Tom?Hanks",?"Al?Pacino",?"Harrison?Ford"?};
????????????var?result1?
=?names.When(name=>name.StartsWith("Tom"));
????????????names[
0]?=?"Stephen?Chou";
????????????var?result2?
=?names.When(name?=>?name.StartsWith("Tom"));


????????????
foreach?(var?name?in?result1)
????????????
{
????????????????Console.WriteLine(name);
????????????}


????????????
foreach?(var?name?in?result2)
????????????
{
????????????????Console.WriteLine(name);
????????????}

}

運(yùn)行程序,你會(huì)發(fā)現(xiàn)兩個(gè)foreach loop顯示的結(jié)果都是一樣的:Tom Hanks。為什么result1實(shí)在第一個(gè)Element被改動(dòng)之前返回的,但我們最終輸出的結(jié)果卻反映的是改動(dòng)之后的數(shù)據(jù)源。通過(guò)我們上面的定義,你很容易得到答案。在這里我要說(shuō)的是LINQ的一個(gè)重要的特性Deferred Evaluation:在調(diào)用Operator的時(shí)候并不會(huì)有任何的任何數(shù)據(jù)獲取的過(guò)程,這個(gè)階段的任務(wù)是創(chuàng)建一個(gè)同于獲取數(shù)據(jù)的表達(dá)式。只要你真正所用到這個(gè)數(shù)據(jù)的時(shí)候,采用重?cái)?shù)據(jù)源中通過(guò)你構(gòu)建的表達(dá)式通過(guò)查詢獲取數(shù)據(jù)。

C# 3.x相關(guān)內(nèi)容:
[原創(chuàng)]深入理解C# 3.x的新特性(1):Anonymous Type
[原創(chuàng)]深入理解C# 3.x的新特性(2):Extension Method - Part I
[原創(chuàng)]深入理解C# 3.x的新特性(2):Extension Method - Part II
[原創(chuàng)]深入理解C# 3.x的新特性(3):從Delegate、Anonymous Method到Lambda Expression
[原創(chuàng)]深入理解C# 3.x的新特性(4):Automatically Implemented Property
[原創(chuàng)]深入理解C# 3.x的新特性(5):Object Initializer 和 Collection Initializer

轉(zhuǎn)載于:https://www.cnblogs.com/artech/archive/2007/07/19/823847.html

總結(jié)

以上是生活随笔為你收集整理的深入理解C# 3.x的新特性(2):Extension Method[下篇]的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。