using static 声明
许多实际的扩展可以通过扩展方法来实现,比如前面的Use扩展方法或前面介绍的用于LINQ的许多扩展方法。在本书后面的许多章节中还将介绍.NET提供的许多扩展方法。
并非所有实际的扩展都有可以扩展的类型。对于某些场景,简单的静态方法比较适合。为了更容易调用这些方法,可以使用using static 声明除去类名。
例如,如果打开了System.Console
using static System.Console;
可以把下面的代码
Console.WriteLine("Hello World!");
改为
WriteLine("Hello World!");
在使用此声明之后,就可以使用类Console的所有静态成员,如WriteLine、Write、ReadLine、Read、Beep等,而不需要编写Console类。只需要确保再打开其他类的静态成员时不要陷入冲突,或者在使用静态方法时不要使用基类的方法。
下面看一个实际的例子。高阶函数以函数作为参数,或者返回一个函数,或者返回两个函数。在处理函数时,可以将两个函数合并到一个函数中。
为此可以使用Compose方法,如下面的代码片段所示:
class FunctionalExtensions
{
public static Func<T1,TResult> Compose<T1,T2,TResult>(
Func<T1,T2> f1,Func<T2,TResult> f2)=>a=>f2(f1(a));
}
该泛型方法定义了三个类型参数和两个委托类型Func的参数。请记住,委托Func<T,Result>引用了一个带有单个参数的方法。其返回类型可以是不同的类型。Compose方法接受两个Func参数,把两个方法组合到一个方法中。传递给Compose的第一个方法(f1)可以有两个不同的类型,一个用于输入(T1),另一个用于输出(T2),而传递的第二个方法(f2)所需要的输入类型(T2)与第一个方法的输出类型(T2)相同,并且可以有不同的输出类型(TResult)。Compose方法本身返回一个Func委托,其输入类型与第一个方法相同(T1),输出类型与第二个方法相同(TResult)。实现可能看起来有点可怕,因为后面跟着连续两个lambda操作符。理解了方法返回的内容(一个方法)时,这个构造就将变得清晰。返回的方法是Func<T1,TResult>。在第一个lambda操作符之后,=>f2(f1(a)); 定义了这个方法。变量的类型为T1,返回的方法类型为TResult,与f2返回的结果类型相同,f2以输入作为参数接收f1。
要使用Compose方法,首先创建两个委托f1和f2,在输入中添加1或2。这些委托会与Compose方法相结合。由于using static 声明打开了类FunctionalExtensions的静态成员,所以可以不使用类名来调用Compose方法。在使用Compose方法创建f3之后,就调用f3方法:
using System;
using static System.Console;
using static usingStatic声明.FunctionalExtensions;
namespace usingStatic声明
{
class Program
{
static void Main(string[] args)
{
Func<int,int> f1 = x=>x+1;
Func<int,int> f2 = x=>x+2;
Func<int,int> f3 = Compose(f1,f2);
var x1 = f3(39);
WriteLine(x1);
}
}
class FunctionalExtensions
{
public static Func<T1,TResult> Compose<T1,T2,TResult>(
Func<T1,T2> f1,Func<T2,TResult> f2)=>a=>f2(f1(a));
}
}
写入控制台的结果当然是42。
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,Marro写入控制台。
完整代码:
using System;
using static System.Console;
using static usingStatic声明.FunctionalExtensions;
namespace usingStatic声明
{
class Program
{
static void Main(string[] args)
{
// Func<int,int> f1 = x=>x+1;
// Func<int,int> f2 = x=>x+2;
// Func<int,int> f3 = Compose(f1,f2);
// var x1 = f3(39);
// WriteLine(x1);
var greetPerson = Compose(new Func<string,Person>(name=>new Person(name)),
person=>$"Hello,{person.FirstName}");
WriteLine(greetPerson("Mario Andretti"));
}
}
class FunctionalExtensions
{
public static Func<T1,TResult> Compose<T1,T2,TResult>(
Func<T1,T2> f1,Func<T2,TResult> f2)=>a=>f2(f1(a));
}
public class Person
{
public Person(string name)=>name.Split(' ').ToStrings(out _firstName,out _lastName);
private string _firstName;
public string FirstName
{
get=>_firstName;
set=>_firstName = value;
}
private string _lastName;
public string LastName
{
get=>_lastName;
set=>_lastName = value;
}
public override string ToString()=>$"{FirstName} {LastName}";
}
public static class StringArrayExtensions
{
public static void ToStrings(this string[] values,out string value1,out string value2)
{
if(values == null) throw new ArgumentNullException(nameof(values));
if(values.Length != 2) throw new IndexOutOfRangeException("only arrays with 2 values allowed");
value1 = values[0];
value2 = values[1];
}
}
}
上一篇: C语言练习笔记 ~ typedef
下一篇: linux中c语言常用内嵌汇编