在C#3.0中,引入了一些列新的特性,比如: Implicitly typed local variable, Extension method,Lambda expression, Object initializer, Anonymous type, Implicitly typed array, Query expression, Expression tree. 个人觉得在这一系列新特性的,最具创新意义的还是Extension method,它从根本上解决了这样的问题:在保持现有Type原封不动的情况下对其进行扩展,你可以在对Type的定义不做任何变动的情况下,为之添加所需的方法成员。在继《深入理解C# 3.0的新特性(1): Anonymous Type 》之后,在这篇文章中,我将介绍我自己对Extension method这个新特性的理解。
一、Prototype in JavaScript
为了说明Extension method到底是为了解决怎样的问题,我首先给出一个类似的、大家都比较熟悉的应用:JavaScript 中的Prototype。
比如我们在JS通过function定义了一个Vector class,代表一个2维向量。
functionVector(x,y)


{
this.x=x;
this.y=y;
}
现在我们需要在不改变Vector定义的前提下,为之添加相关的进行向量运算的Method。比如我们现在需要添加一个进行两个向量相加运算的adds方法。在JS中,我们很容易通过Prototype实现这一功能:
Vector.prototype.adds=function(v)


{
if(vinstanceofVector)


{
returnnewVector(this.x+v.x,this.y+v.y);
}
else


{
alert("InvalidVectorobject!");
}
}
那么,通过添加上面的一段代码,我们完全可以把adds方法作为Vector的一个方法成员。现在我们可以这样的方式来写代码:
varv=newVector(1,2);
v=v.adds(v);
alert("x="+v.x+",y="+v.y);
Extension Method之于C# 3.0就如同Prototype之于JavaScript。
二、如何在C# 2.0中解决Type的扩展性
我们一个完全一样的问题从弱类型、解释型的编程语言JavaScript迁移到C#这种强类型、编译型的语言上来。我们先看看在不能借助Extension Method这一新特性的C# 2.0中,我们是如何解决这一问题。
我们先来看看如何对一个Interface进行扩张。假设我们有如下的一个IVector interface的定义:
publicinterfaceIVector


{

doubleX
{get;set;}

doubleY
{get;set;}
}
我们希望的是如何对这个Interface进行扩展,为之添加一个Adds Method执行向量相加的运算。我们唯一的解决方案就是直接在这个Interface中添加一个Adds成员:
publicinterfaceIVector


{

doubleX
{get;set;}

doubleY
{get;set;}
IVectorAdds(IVectorvector);
}
由于Interface和实现它的Type的紧密联系:所以实现了某个Interface的Type必须实现该Interface的所有方法。所以,我们添加了Adds Method,将导致所有实现它的Type的重新定义和编译,在很多情况下,这种代价我们是负担不起的:比如在系统的后期维护阶段,对系统的进行局部和全部的重新编译,将很有可以导致一个正常运行的系统崩溃。Interface的这种局限性在面向抽象设计和编程中应该得到充分的考虑,这也是我们在很多情况下宁愿使用Abstract Class的一个主要原因。
上面说到了对Interface的扩展,会出现必须实现Interface的Type进行改动的风险。我想有人会说,对Class尽心扩展就不会出现这样的情况了吧。不错,Class的继承性确保我们在Parent class添加的Public/Protect能被Child Class继承。比如:如果Vector是一个Super Class:
publicclassVector


{
privatedouble_x;
privatedouble_y;

publicdoubleX


{

get
{returnthis._x;}

set
{this._x=value;}
}

publicdoubleY


{

get
{returnthis._y;}

set
{this._y=value;}
}
}
如果我们在Vector Class中添加一个Adds Method,所有的Child Class都不会受到影响。
但是在很多情况下,对于我们需要扩展的Interface或者是Type,我们是完全不能做任何改动。比如,某个Type定义在一个由第三方提供的Assembly中。在现有的情况下,对于这样的需求我们将无能为力。我们常用的方法就自己定义的Class去继承这个需要扩展,将需要添加的成员定义在我们自己定义的Class中,如果对于一个Sealed Class又该如何呢?即便不是Sealed Class,这作用方式也没有完成我们预定的要求:我们要求的是对这个不能变动的Type进行扩展,也就是所这个不能变动的Type的Instance具有我们添加的对象。
如果你在完全了解Extension Method的前提下听到这样的要求:我们要对一个Type或者Interface进行扩展,却不允许我们修改它。这个要求确实有点苛刻。但是,不能否认的是,这样需要在现实中的运用是相当广泛的。所以我说,Extension Method在所有提供的新特性中,是具有价值的一个。
三、C# 3.0中如何解决Type的扩展性
理解了我们的具体需要和现有编程语言的局限性后,我们来看看C# 3.0中是如何通过Extension Method解决这个问题的。
简单地说Extension Method是一个定义在Static Class的一个特殊的Static Method。之所以说这个Static Method特别,是因为Extension Method不但能按照Static Method的语法进行调用,还能按照Instance Method的语法进行调用。
我们还是先来看例子,首先是我们需要进行扩展的Vector Type的定义:
publicclassVector


{
privatedouble_x;
privatedouble_y;

publicdoubleX


{

get
{returnthis._x;}

set
{this._x=value;}
}

publicdoubleY


{

get
{returnthis._y;}

set
{this._y=value;}
}
}
在不对Vector Class的定义进行更新的前提下,我们把需要添加的Adds方法定义在一个Static Class中:
publicstaticclassExtension


{
publicstaticVectorAdds(thisVectorp,Vectorp1)


{

returnnewVector
{X=p.X+p1.X,Y=p.Y+p1.Y};
}
}
这个Extension Method:Adds是一个Static方法。和一般的Static方法不同的是:在第一个参数前添加了一个this 关键字。这是在C# 3.0中定义Extension Method而引入的关键字。添加了这样一个关键字就意味着在调用该方法的时候这个标记有this的参数可以前置,从而允许我们向调用一般Instance Method的方式来调用这个Static Method。比如:
classProgram


{
staticvoidMain(string[]args)


{

varv=newVector
{X=1,Y=2};
v=v.Adds(v);
Console.WriteLine("v.X={0}andv.Y={1}",v.X,v.Y);
}
}
注:this关键字只能用于标记第一个参数。
通过上面的介绍,我们知道在C# 3.0如何通过定义Extension Method在不对Type作任何修改的前提下对Type进行扩展。至于Extension Method的本质:C# Compiler在编译Extension Method时会做怎样处理;在最终被编译成的Assembly中相关的IL具有怎样的特征;Extension Method的优先级,如果有兴趣,可以参考《[原创]深入理解C# 3.0的新特性(2):Extension Method - Part II》,此外在第二部分中,我会给出一个完整的Sample:通过Extension Method定义一个形如LINQ中常见的Operator,完成基于LINQ的查询功能。
C# 3.x相关内容:
[原创]深入理解C# 3.x的新特性(1):Anonymous Type
[原创]深入理解C# 3.x的新特性(2):Extension Method - Part I
[原创]深入理解C# 3.x的新特性(2):Extension Method - Part II
[原创]深入理解C# 3.x的新特性(3):从Delegate、Anonymous Method到Lambda Expression
[原创]深入理解C# 3.x的新特性(4):Automatically Implemented Property
[原创]深入理解C# 3.x的新特性(5):Object Initializer 和 Collection Initializer
分享到:
相关推荐
这部分内容是继【C#.NET案例开发集锦代码part1】之后的延续,旨在帮助开发者深入理解和掌握C#.NET的实用技巧。通过下载并学习这些代码,你可以提升在C#.NET环境下进行软件开发的能力。 1. **控件应用**:C#.NET提供...
- **.NET 4.5.x**: Introduces asynchronous programming, enhanced file I/O, and improved support for parallelism. - **.NET 4.6 (Aligned with Visual Studio 2015)**: Enhancements include improved ...
Based on the provided information from the book "C# 3.0 With the .NET Framework 3.5 Unleashed," we can extract several key points and concepts that are essential for understanding the fundamentals of ...
Other part of uIntelliSense is an optional Visual Studio extension for Visual Studio 2012 and newer, for even better experience: In-IDE integrated Scripting Reference browser, Quick Search for Unity ...
How to leverage all the new LINQ relevant C# 2008 language features including extension methods, lambda expressions, anonymous data types, and partial methods. How to use LINQ to Objects to query in-...
Part I: The C# Language 38 Chapter 1: Introducing C# 40 What Is the .NET Framework? 40 What Is C#? 45 Visual Studio 2008 46 Summary 48 Chapter 2: Writing a C# Program 50 The ...
Added discussion of events and thread-safety as well as showing a cool extension method to simplify the raising of an event. Chapter 12-Generics 新增讨论了委托和接口泛型类型参数的不同。 Chapter 13...
CLR via C# 第4版 英文PDFKristin, words cannot express how /feel about our life together. cherish our family and all our adventures. I'm filled each day with love for Aidan (age 9)and Grant (age 5), ...