【.NET Core】匿名方法与扩展方法
文章目录
- [【.NET Core】匿名方法与扩展方法](#【.NET Core】匿名方法与扩展方法)
-
- 一、匿名方法
-
- [1.1 匿名方法定义](#1.1 匿名方法定义)
- [1.2 通过Delegate关键字创建委托匿名方法](#1.2 通过Delegate关键字创建委托匿名方法)
- [1.3 通过Action关键字创建无返回值的匿名方法](#1.3 通过Action关键字创建无返回值的匿名方法)
- [1.4 通过Func关键字创建有返回值的匿名方法](#1.4 通过Func关键字创建有返回值的匿名方法)
- [1.5 使用Lambda表达式表示匿名方法](#1.5 使用Lambda表达式表示匿名方法)
- 二、扩展方法
-
- [2.1 扩展方法定义](#2.1 扩展方法定义)
- [2.2 编译时的扩展方法](#2.2 编译时的扩展方法)
- [2.3 值类型如何定义扩展方法](#2.3 值类型如何定义扩展方法)
- [2.4 如何定义和调用扩展方法](#2.4 如何定义和调用扩展方法)
一、匿名方法
1.1 匿名方法定义
委托是用于引用与其具有相同标签的方法。可以使用委托对象调用可由委托引用的方法。匿名方法(Anonymous methods)
提供了一种传递代码块作为委托参数的技术。匿名方法是没有名称只有主体的方法。在匿名方法中不需要指定返回类型,它是从方法主体内的return语句推断而来。
1.2 通过Delegate关键字创建委托匿名方法
匿名方法可以通过delegate来声明一个委托的匿名方法声明。
示例如下:
c#
public class Program
{
//无返回值的匿名方法
public delegate void MethodParameterFree(string name);
MethodParameterFree MethdFree = delegate (string name)
{
Console.WriteLine($"无参的匿名方法,输出值={name}");
};
//有返回值,且返回值为string匿名方法
public delegate string MethodParameterReturnString(string name);
MethodParameterReturnString methodParameterReturn = delegate (string name)
{
return $"有参的匿名方法,返回值为:{name}";
};
public static void Main(string[] args)
{
Program program= new Program();
program.MethdFree("MethodParameterFree.");
string response= program.methodParameterReturn("ReturnValue");
Console.WriteLine(response);
}
}
1.3 通过Action关键字创建无返回值的匿名方法
示例如下:
c#
Action<string> MethdFree = (string name)=>
{
Console.WriteLine($"无参的匿名方法,输出值={name}");
};
public static void Main(string[] args)
{
Program program= new Program();
program.MethdFree("MethodParameterFree.");
}
1.4 通过Func关键字创建有返回值的匿名方法
c#
Func<string,int,string> MethdFunc = (string name,int age)=> $"Func匿名方法,姓名={name},年龄={age}";
public static void Main(string[] args)
{
Program program= new Program();
string response= program.MethdFunc("Goyeer",39);
Console.WriteLine(response);
}
隐式输入参数匿名函数
c#
Func<string,int,string> MethdFunc = (name,age)=> $"Func匿名函数,姓名={name};年龄={age}";
public static void Main(string[] args)
{
Program program= new Program();
string response= program.MethdFunc("Goyeer",39);
Console.WriteLine(response);
}
使用弃元指定Lambda表达式中未使用的参数
c#
Func<string,int,string> MethdFunc = (_,_)=> $"Func弃元,处理未使用匿名方法。";
public static void Main(string[] args)
{
Program program= new Program();
string response= program.MethdFunc("Goyeer",39);
Console.WriteLine(response);
}
1.5 使用Lambda表达式表示匿名方法
c#
public static void Main(string[] args)
{
var RetrunValueMethod = (string name, int age) => {
Console.WriteLine($"Lambda表达式无返回值匿名方法,姓名={name},年龄={age}");
};
RetrunValueMethod("GOYEER",42);
//Lambda有返回值
var MethdFunc = (string name, int age) => $"Func Lambda表达式表示匿名方法,姓名={name},年龄={age}。";
Console.WriteLine(MethdFunc("Gogeer",39));
}
二、扩展方法
2.1 扩展方法定义
扩展方法使用你能够向现有类型添加方法,而无需创建新的派生类型,重新编译或以其他方式修改原始类型。扩展方法是一种静态方法,但可以像扩展类型上的实例方法一样进行调用。调用扩展方法与调用在类型中定义方法没有明显区别。
最常用的扩展方法是LINQ标准查询运算符,它将查询功能添加到现有的System.Collections.IEnumerable
和System.Collections.Generic.IEnumerable<T>
类型。
扩展方法被定义为静态方法,它们是通过实例方法语法进行调用的。它们的第一参数指定方法操作的类型。参数前面是此修饰符。仅当你使用using
指令将命名空间显示导入到源代码中之后,扩展方法才位于范围中。
2.2 编译时的扩展方法
可以使用扩展方法来扩展类或接口,但不能重写扩展方法。与接口或类方法具有相同名称和签名的扩展方法永远不会被调用。编译时,扩展方法的优先级总是比类型本身中的实例方法底。如果某个类型具有一个名为Process(int i)
的方法,而你有一个具有相同签名的扩展方法,则编译器总是绑定到该实例方法。当编译器遇到方法调用时,它首先在该类型的实例方法中寻找匹配的方法。如果未找到任何匹配的方法,编译器将搜索为该类型定义的任何扩展方法,并且绑定到它找到的第一个扩展方法。
2.3 值类型如何定义扩展方法
使用struct
类型扩展预定义类型可能很困难,因为他们已通过值传递给方法。这意味着将对结构的副本进行任何结构更改。扩展方法退出后,将不显示这些更改。可以将ref
修饰符添加到第一个参数,使其成为ref
扩展方法。ref
关键字可以在this
关键字之前或之后显示,不会有任何语义差异。添加ref
修饰符表示第一个参数是按引用传递的,在这种情况下,可以编写扩展方法更改要扩展的值类型。扩展方法仅允许值类型或受结构约束的泛型类型作为ref
扩展方法的第一参数。
c#
public static class IntExtensions
{
public static void Increment(this int number)
=> number++;
public static void RefIncrement(this ref int number)
=> number++;
}
public static class IntProgram
{
public static void Test()
{
int x = 1;
x.Increment();
Console.WriteLine($"x is now {x}"); //输出结果: x is now 1
x.RefIncrement();
Console.WriteLine($"x is now {x}"); //输出结果: x is now 2
}
}
2.4 如何定义和调用扩展方法
- 定义包含扩展方法的静态类。此类必须对客户端代码可见。
- 将扩展方法实现为静态方法,并且使用可见性至少与所在类的可见性相同。
- 此方法的第一个参数指定方法所操作的类型;此参数前必须加上
this
修饰符,值类型需要变更变量值的需要在this后ref
关键字。 - 在调用代码中,添加
using
指令,用于指定包含扩展方法类的命名空间 - 和调用类型的实例方法那样调用这些方法。
第一个参数并不是由调用代码指定,因为它表示要在其上应用运算符的类型,并且编译器已经知道对象的类型。
示例
C#
public static class MyExtensions
{
public static int WordCount(this string str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}