许多实际的扩展可以通过扩展方法来实现,并非所有实际的扩展都有可以扩展的类型。对于某些场景,简单的静态方法比较适合。为了更容易调用这些方法,可以使用 using static 声明除去类名。
例如,如果打开了 System.Console
using static System.Console;
可以把下面的代码
Console.WriteLine("Hello World!");
改为
WriteLine("Hello World!");
在使用此声明之后,就可以使用类 Console 的所有静态成员,如 WriteLine、Write、ReadLine、Read、Beep 等,而不需要编写 Console 类。只需要确保在打开其他类的静态成员时不要陷入冲突,或者在使用静态方法时不要使用基类的方法。
下面看一个实际的例子。高阶函数以函数作为参数,或者返回一个函数,或者返回两个函数。在处理函数时,可以将两个函数合并到一个函数中。
“
为此可以使用Compose 方法,如下面的代码片段所示:
public static class FunctionalExtensions
{//...public static Func<T1, TResult> Compose<T1, T2, TResult>(Func<T1, T2> fl, Func<T2, TResult> f2) => a => f2(f1(a));
}
该泛型方法定义了三个类型参数和两个委托类型 Func 的参数。请记住,委托 Func<T,TResult>引用了一带有单个参数的方法,其返回类型可以是不同的类型。Compose 方法接受两个 Func 参数,把两个方法组合到一个方法中。传递给Compose 的第一个方法(f1)可以有两个不同的类型,一个用于输入 T,另一个用于输出(T2),而传递的第二个方法(f2)所需要的输入类型(T2)与第一个方法的输出类型(T2)相同,并且可以有不同的输出类(TResult)。Compose 方法本身返回一个 Func 委托,其输入类型与第一个方法相同(T),输出类型与第二个方相同(TResult)。实现可能看起来有点可怕,因为后面跟着连续两个 lambda 操作符。理解了方法返回的内容(一个方法)时,这个构造就将变得清晰。返回的方法是 Func<T1,TResult>。在第一个 lambda 操作符之后,=>f2(f1(2));定义了这个方法。变量的类型为 T1,返回的方法类型为 TResult,与 f2 返回的结果类型相同,f2 以输入作为参数接收 f1。
要使用 Compose 方法,首先创建两个委托 f1 和 f2,在输入中添加 1 或 2。这些委托会与 Compose 方法相结合。由于 usingstatic 声明打开了类 FunctionalExtensions 的静态成员,所以可以不使用类名来调用 Compose 方法。在使用 Compose 方法创建 f3之后,就调用 f3 方法:
using System;
using static System.Console;
using static UsingStatic.FunctionalExtensions;
namespace UsingStatic
{class Program{static void Main(){//...Func<int, int> f1 = x => x + 1;Func<int, int> f2 = x => x + 2;Func<int, int> f3 = Compose(f1, f2);var xl = f3(39); WriteLine(x1);//...}}
}
写入控制台的结果当然是 42。
声明 Compose 方法时,参数类型可以在输入和输出之间有所不同。在下面的代码片段中,传递给 Compose 方法的第一个方法接收一个字符串,并返回 Person 对象;第二个方法接收 Person 并返回一个字符串。如果编译器不能从变量和返回类型中识别参数类型,就必须指定具体的委托类型,方法是接收字符串并返回一个 Person。只有变量名,并不能帮助编译器确定它的类型。通过传递给 Compose 方法的第二个方法,显然,输入的类型与第一个方法返回的类型相同,因此不需要指定类型。在调用Compose 方法之后,变量 greetPerson 是两个输入方法的组合:
var greetPerson = Compose(new Func<string, Person>(name => new Person(name)),person => $"Hello, {person.FirstName}"); WriteLine(greetPerson("Mario Andretti"));
在WriteLine 方法中使用字符串 Mario Andretti 调用greetPerson 方法将字符串 Hello,Mario 写入控制台。