C#中的委托是什么-下(Func与Action)

参考资料:
《C# 7.0本质论》13.2

Func委托
Action委托
委托的内部机制

自从C#3.0后,有了Func委托与Action委托,我们几乎不用再自己声明委托了。

Func委托

System.Func系列委托代表有返回值的方法。

Func委托的声明,in符号后是接受的参数类型,out符号后是返回的值类型:

public delegate TResult Func<out TResult>();
public delegate TResult Func<in T1, out TResult>(T1 arg1);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
...
public delegate TResult Func<in T1,in T2,in T3,in T4,in T5,in T6,in T7,in T8,in T9,in T10,in T11,in T12,in T13,in T14,in T15,in T16,out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);

假设有一个方法BubbleSort,它当然是用来排序的方法,但排序的规则不固定,可能要从大到小,可能要从小到大。比起在方法内部用if或者switch等语句来实现,用Func委托是一个更好的选择。

// BubbleSort接受一个int型数组,接受一个Func委托,该委托接受两个int型参数,返回值类型为bool
public static void BubbleSort(int[] items, Func<int, int, bool> compare)
{
    // ...

}

public static bool GreaterThan(int first, int second)
{
    return first > second;
}

static void Main(string[] args)
{
    int[] items = { 1, 3, 2, 4, 5 };

    // 把GreaterThan方法作为BubbleSort方法的第二个参数传入
    BubbleSort(items, GreaterThan);
    // ...
}

如果想把比较的规则改为first < second,只需要实现方法LessThan,然后传给BubbleSort即可。使用lambda表达式是一种简单的方法。例如:

BubbleSort(items, (first,second) => first > second);

Action委托

System.Action系列代表返回void的方法。

Action委托的声明,in符号后是接受的参数类型:

public delegate void Action();
public delegate void Action<in T>(T obj);
public delegate void Action<in T1,in T2>(T1 arg1, T2 arg2);
public delegate void Action<in T1,in T2,in T3>(T1 arg1, T2 arg2, T3 arg3);
...
public delegate void Action<in T1,in T2,in T3,in T4,in T5,in T6,in T7,in T8,in T9,in T10,in T11,in T12,in T13,in T14,in T15,in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);

这里就不举例了。

委托的内部机制

委托实际是特殊的类。虽然C#标准没有明确说明类的层次结构,但委托必须直接或间接派生自System.Delegate。事实上,.NET委托总是派生自System.MulticastDelegate,后者又从System.Delegate派生,图为委托类型的对象模型:

所有委托都不可变(immutable)。委托创建好后无法更改。如变量包含委托引用,并想引用不同的方法,只能创建新委托再把它赋给变量。委托执行+=与-=操作时实际也是新建了一个委托。

虽然所有委托数据类型都间接从System.Delegate派生,但C#编译器不允许声明直接/间接从System.Delegate或者System.MulticastDelegate派生的类。

原文地址:https://www.cnblogs.com/Kit-L/p/13861829.html