如何以及为何在 C# 中使用委托
介绍
有可能我们编写代码多年都没有刻意使用delegate、Action或Func类型。我说“刻意”是因为我们可能在不知不觉中使用过它们。
了解这些类型代表什么可以让阅读代码变得更容易。了解如何使用它们可以为我们的开发人员工具箱添加一些有用的工具。
什么是代表?
委托是一种表示具有特定签名和返回类型的方法的类型。
委托的声明与方法的声明完全相同,只是前面有关键字delegate 。
例子:
表示将两个数字相加并返回结果的方法的委托:
delegate int AddNumbers(int value1, int value2);表示记录异常并且不返回任何内容的方法的委托:
delegate void LogException(Exception ex);表示将某些泛型类型转换为字符串的函数的委托:
delegate string FormatAsString<T>(T input);
就像类和接口一样,我们可以在类外部或嵌套在类中声明委托。我们可以将它们标记为private、public或internal。
我们可以分配给代表什么?
我们可以为任何与委托签名匹配的方法分配一个引用。
例如,假设我们有以下委托和类:
delegate double MathCalculation(float value1, float value2);
public static class Calculator
{
public static double AddNumbers(float value1, float value2) => value2 + value2;
public static double DivideNumbers(float value1, float value2) => value1 / value2;
}
我们可以将任一方法分配给声明为MathCalculation类型的变量:
MathCalculation add = Calculator.AddNumbers;
MathCalculation divide = Calculator.DivideNumbers;
我们如何“召唤”代表?
调用委托引用的方法称为调用委托。我们可以使用Invoke方法执行此操作:
var result = add.Invoke(2, 3);
或者不使用Invoke方法:
var result = divide(100, 3);
什么是动作和功能?
Action和Func是委托,我们可以使用它来代替定义自己的委托类型。记住这一点很重要:Action和Func 是委托。
例如,不要声明MathCalculation委托并分配以下内容,
MathCalculation add = Calculator.AddNumbers;
我们可以指定:
Func<float, float, double> add = Calculator.AddNumbers;
我们使用Func<>来表示返回某些内容的方法。如果函数有参数,则第一个泛型参数表示这些参数。最后一个泛型参数表示返回类型。Func <int, DateTime, string>是一个带有int和DateTime参数的函数,它返回一个字符串。
Action和Action<>表示不返回任何内容的方法。Action没有参数。Action < string, int>表示带有字符串和int参数的方法。
我应该使用 Action 或 Func 还是声明委托?
Action或Func或声明委托本质上是可以互换的。声明委托允许我们为其指定一个名称,以表明其用途。名为MathCalculation的委托显然旨在进行数学运算。Func <float, float, double>不会告诉我们该方法的作用。
这是一种偏好和一个逐个案例的决定。委托可能更清晰,但是Action和Func使我们不必声明更多的委托类型,并且通常在用途明显时就足够了。
我们可以像其他类型一样传递委托、动作和函数
如果您使用 LINQ,那么您已经完成了此操作。请考虑以下示例:
int[] numbers = {1, 5, 1000, 10};
var bigNumbers = numbers.Where(n => n > 999);
我们实际上创建了一个匿名Func<int, bool> - 一个接受int并返回 true 或 false 的函数 - 并将该函数作为参数传递给Where方法。然后,Where方法对列表中的每个项目执行该函数以查看其为 true 还是 false。
如果我们的类有一个具有相同签名的函数,例如:
bool IsBigNumber(int number) => number > 499;
然后我们可以将该函数作为参数传递给Where:
var bigNumbers = numbers.Where(IsBigNumber);
我们可以编写自己的方法,将函数作为参数。例如,这个泛型方法接受List<T>和Func<T, bool>,并使用它来返回列表中条件不成立的所有项目:
List<T> Exclude<T>(List<T> values, Func<T, bool> condition)
{
return values.Where(value => !condition(value)).ToList();
}
它的工作原理是获取传递给Exclude方法的Func<T, bool>并将该函数传递给Where方法。
返回函数的函数
我们还可以从函数返回函数。假设我们要过滤和排序一个集合,但我们想根据变量更改排序顺序。我们可能有一个用于不同排序顺序的枚举:
public enum SortOrder { FirstName, LastName, BirthDate }
当我们调用 LINQ 的OrderBy方法时,我们会向其传递一个函数,该函数返回要排序的值。我们可以编写一个函数,该函数使用一个变量并确定要按Person的哪个属性进行排序:
Func<Person, IComparable> GetSortFunction(SortOrder sortOrder)
{
switch (sortOrder)
{
case SortOrder.FirstName:
return person => person.FirstName;
case SortOrder.BirthDate:
return person => person.BirthDate;
default:
return person => person.LastName;
}
}
然后我们可以按如下方式使用该变量:
IEnumerable<Person> SortAndFilter(IEnumerable<Person> people, SortOrder sortOrder)
{
var sortFunction = GetSortFunction(sortOrder);
return people.Where(person => person.Active).OrderBy(sortFunction);
}
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~