引MSDN对扩展方法的定义: 扩展方法使你能够向现有类型“添加”方法(包括你自定义的类型和对象噢),而无需创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一种特殊的静态方法,但是可以像扩展类型上的实例方法一样进行调用。对于用C#编写的客户端代码,调用扩展方法与调用在类型中实际定义的方法之间没有明显的差异。
LINQ标准查询运算符就是采用的扩展方法方式,见图
(当我们看到下“小标箭头”的方法就是扩展方法了,这里我们看到OrderBy亦是扩展方法)
LINQ应用:
class ExtensionMethods2
{
static void Main()
{
int[] ints = { 1,3,2,4,6,8,10};
var result = ints.OrderBy(g => g);
foreach (var i in result)
{
System.Console.Write(i + " ");
}
}
}
这里var result = ints.OrderBy(g=>g);又引入了Lamada表达式(“拉姆达”),我们顺便看下Lamada的用法吧:
Lamada表达式是一个匿名函数,他可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。
关键我们看下他如何是一个匿名函数:
稍加修改一下上面的代码,var result = ints.Count(g=>g%2==0);这里引入的匿名函数表示查找所有能被2整除的数;
总结,所有Lamada表达式都采用=>运算符,该运算符号我们一般读为“goes to”。Lamada运算符的左边是输入参数(如果有参数),右边包含表达式或语句块。Lamada表达式X=>X*X读作
“X goes to X times X” 。 可以将此表达式分配给委托类型,如下:
delegate int test(int i);
test myDelegate = x => x * x;
int j = myDelegate(5);
//结果输出 25
我们再看一下Lamada表达式如何被应用与创建目录树类型,这个一般是应用在基于方法的LINQ查询中。
使用基于方法的语法在 Enumerable 类中调用 Where 方法时(像在 LINQ to Objects 和 LINQ to XML 中那样),参数是委托类型 System..::.Func<(Of <(T, TResult>)>)。使用 Lambda 表达式创建委托最为方便。例如,当您在 System.Linq..::.Queryable 类中调用相同的方法时(像在 LINQ to SQL 中那样),则参数类型是 System.Linq.Expressions..::.Expression<Func>,其中 Func 是包含至多五个输入参数的任何 Func 委托。
示例:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);//输出出现在“9”之前的所有元素
讲了这么多关于Lamada表达式的东东,偶们还是回到这篇的正题:扩展方法 。
简单的扩展方法:
//扩展方法定义
public static class test
{
public static bool In(this object o, IEnumerable c)
{
foreach (object obj in c)
if (obj.Equals(o))
return true;
return false;
}
}
//下面是调用代码
string[] list = new string[] { "abc" , "123", "java"};
Console.WriteLine("java".In(list));
//输出true
自定义对象上的扩展方法:
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
public static class test
{
public static bool IsValue(this Student student, object o)
{
if (student.Name == o)
{
return true;
}
return false;
}
}
//代码调用
Student student = new Student { Name = "布颜书", Age = 24};
Console.WriteLine(student.IsValue("布颜书"));
//输出true
慎用扩展方法:
通常,建议您只在不得已的情况下才实现扩展方法,并谨慎地实现。只要有可能,必须扩展现有类型的客户端代码都应该通过创建从现有类型派生的新类型来达到这一目的。
在使用扩展方法来扩展您无法更改其源代码的类型时,您需要承受该类型实现中的更改会导致扩展方法失效的风险。
如果您确实为给定类型实现了扩展方法,请记住以下两点:
-
如果扩展方法与该类型中定义的方法具有相同的签名,则扩展方法永远不会被调用。
-
扩展方法被在命名空间级别放入范围中。例如,如果您在同一个名为 Extensions 的命名空间中具有多个包含扩展方法的静态类,则这些扩展方法将全部由 using Extensions; 指令放入范围中。
类库的实施者不应使用扩展方法来避免创建程序集的新版本。如果您要向库中添加重要的新功能,并且您拥有源代码,则应该遵循标准 .NET Framework 程序集版本控制准则。