I. Action
/Func
委托的区别在于参数是单独的参数还是n-tuple格式的参数:
// 1. Action with 3 distinct 'int' parameters
Action<int, int, int> ArgsAction = (i1, i2, i3) => i1 += i2 += i3;
// 2. Func with 3 distinct 'int' parameters, returning 'long'
Func<int, int, int, long> ArgsFunc = (i1, i2, i3) => (long)i1 + i2 + i3;
// 3. Action with a single 3-tuple parameter
Action<(int, int, int)> TupleAction = args => args.Item1 += args.Item2 += args.Item3;
// 4. Action with a single 3-tuple parameter, returning 'long'
Func<(int, int, int), long> TupleFunc = args => (long)args.Item1 + args.Item2 + args.Item3;
II. 展示上述示例的直接使用方法
long r;
// pass distinct params to multi-arg methods
ArgsAction(1, 2, 3); // 1.
r = ArgsFunc(1, 2, 3); // 2.
// pass tuple to tuple-taking methods
TupleAction((1, 2, 3)); // 3.
r = TupleFunc((1, 2, 3)); // 4.
下面两个部分的示例都会以它们各自的非本地参数形式调用委托。如果需要推迟方法调用或保留适配的委托以进行缓存或延迟/多次调用场景,请参见VI和VII。
III. 将元组分散(“splat”)到多个参数的方法中。
(1, 2, 3).Scatter(ArgsAction)
r = (1, 2, 3).Scatter(ArgsFunc)
IV. 将不同的参数传递给接受元组的方法:
TupleAction.Gather(1, 2, 3)
r = TupleFunc.Gather(1, 2, 3)
V. 扩展方法 Scatter
和 Gather
在上述(III)和(IV)中被使用:
public static void Scatter<T0, T1>(in this (T0 i0, T1 i1) t, Action<T0, T1> a) => a(t.i0, t.i1);
public static void Scatter<T0, T1, T2>(in this (T0 i0, T1 i1, T2 i2) t, Action<T0, T1, T2> a) => a(t.i0, t.i1, t.i2);
public static void Scatter<T0, T1, T2, T3>(in this (T0 i0, T1 i1, T2 i2, T3 i3) t, Action<T0, T1, T2, T3> a) => a(t.i0, t.i1, t.i2, t.i3);
public static TResult Scatter<T0, T1, TResult>(in this (T0 i0, T1 i1) t, Func<T0, T1, TResult> f) => f(t.i0, t.i1);
public static TResult Scatter<T0, T1, T2, TResult>(in this (T0 i0, T1 i1, T2 i2) t, Func<T0, T1, T2, TResult> f) => f(t.i0, t.i1, t.i2);
public static TResult Scatter<T0, T1, T2, T3, TResult>(in this (T0 i0, T1 i1, T2 i2, T3 i3) t, Func<T0, T1, T2, T3, TResult> f) => f(t.i0, t.i1, t.i2, t.i3);
public static void Gather<T0, T1>(this Action<(T0, T1)> a, T0 i0, T1 i1) => a((i0, i1));
public static void Gather<T0, T1, T2>(this Action<(T0, T1, T2)> a, T0 i0, T1 i1, T2 i2) => a((i0, i1, i2));
public static void Gather<T0, T1, T2, T3>(this Action<(T0, T1, T2, T3)> a, T0 i0, T1 i1, T2 i2, T3 i3) => a((i0, i1, i2, i3));
public static TResult Gather<T0, T1, TResult>(this Func<(T0, T1), TResult> f, T0 i0, T1 i1) => f((i0, i1));
public static TResult Gather<T0, T1, T2, TResult>(this Func<(T0, T1, T2), TResult> f, T0 i0, T1 i1, T2 i2) => f((i0, i1, i2));
public static TResult Gather<T0, T1, T2, T3, TResult>(this Func<(T0, T1, T2, T3), TResult> f, T0 i0, T1 i1, T2 i2, T3 i3) => f((i0, i1, i2, i3));
VI. 奖励回合。如果你计划在其替代形式中多次调用一个接受元组或不同参数的委托,或者你还没有准备好实际调用它,那么你可能希望显式地将委托从接受元组形式转换为等效的不同参数委托,反之亦然。你可以缓存转换后的委托以供多次或任意后续重用。
var ga = ArgsAction.ToGathered();
ga((1, 2, 3));
ga((4, 5, 6));
var gf = ArgsFunc.ToGathered();
r = gf((1, 2, 3));
r = gf((4, 5, 6));
var sa = TupleAction.ToScattered();
sa(1, 2, 3);
sa(4, 5, 6);
var sf = TupleFunc.ToScattered();
r = sf(1, 2, 3);
r = sf(4, 5, 6);
ArgsAction.ToGathered()((1, 2, 3));
r = ArgsFunc.ToGathered()((1, 2, 3));
TupleAction.ToScattered()(1, 2, 3);
r = TupleFunc.ToScattered()(1, 2, 3);
VII. 在VI中展示的奖励示例中使用的扩展方法。
public static Action<T0, T1> ToScattered<T0, T1>(this Action<(T0, T1)> a) => (i0, i1) => a((i0, i1));
public static Action<T0, T1, T2> ToScattered<T0, T1, T2>(this Action<(T0, T1, T2)> a) => (i0, i1, i2) => a((i0, i1, i2));
public static Action<T0, T1, T2, T3> ToScattered<T0, T1, T2, T3>(this Action<(T0, T1, T2, T3)> a) => (i0, i1, i2, i3) => a((i0, i1, i2, i3));
public static Func<T0, T1, TResult> ToScattered<T0, T1, TResult>(this Func<(T0, T1), TResult> f) => (i0, i1) => f((i0, i1));
public static Func<T0, T1, T2, TResult> ToScattered<T0, T1, T2, TResult>(this Func<(T0, T1, T2), TResult> f) => (i0, i1, i2) => f((i0, i1, i2));
public static Func<T0, T1, T2, T3, TResult> ToScattered<T0, T1, T2, T3, TResult>(this Func<(T0, T1, T2, T3), TResult> f) => (i0, i1, i2, i3) => f((i0, i1, i2, i3));
public static Action<(T0, T1)> ToGathered<T0, T1>(this Action<T0, T1> a) => t => a(t.Item1, t.Item2);
public static Action<(T0, T1, T2)> ToGathered<T0, T1, T2>(this Action<T0, T1, T2> a) => t => a(t.Item1, t.Item2, t.Item3);
public static Action<(T0, T1, T2, T3)> ToGathered<T0, T1, T2, T3>(this Action<T0, T1, T2, T3> a) => t => a(t.Item1, t.Item2, t.Item3, t.Item4);
public static Func<(T0, T1), TResult> ToGathered<T0, T1, TResult>(this Func<T0, T1, TResult> f) => t => f(t.Item1, t.Item2);
public static Func<(T0, T1, T2), TResult> ToGathered<T0, T1, T2, TResult>(this Func<T0, T1, T2, TResult> f) => t => f(t.Item1, t.Item2, t.Item3);
public static Func<(T0, T1, T2, T3), TResult> ToGathered<T0, T1, T2, T3, TResult>(this Func<T0, T1, T2, T3, TResult> f) => t => f(t.Item1, t.Item2, t.Item3, t.Item4);
f(*args)
和Javascript中的f(...args)
的等价性。 - Daniel Chin