比如我有
private void test(Action> fn) { fn(("hello", 10)); } test(t => { var (s, i) = t; Console.WriteLine(s); Console.WriteLine(i); });
我想写这样的东西
private void test(Action> fn) { fn(("hello", 10)); } test((s,i) => { Console.WriteLine(s); Console.WriteLine(i); });
这有可能用一些正确的表示法吗?
您可以将其缩短为:
void test( Action> fn) { fn(("hello", 10)); } test(((string s, int i) t) => { Console.WriteLine(t.s); Console.WriteLine(t.i); });
希望有一天我们可以将参数从元组映射到方法调用:
void test(Action> fn) { fn(@("hello", 10)); // <-- made up syntax } test((s, i) => { Console.WriteLine(s); Console.WriteLine(i); });
但目前还没有.
I.具有distingle-args与单个n元组参数的Action
/ Func
委托示例:
// 1. Action with 3 distinct 'int' parameters ActionArgsAction = (i1, i2, i3) => i1 += i2 += i3; // 2. Func with 3 distinct 'int' parameters, returning 'long' Func 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;
二。演示直接使用上述示例
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。
三,将元组分散(“ splat”)到多参数方法中。
(1, 2, 3).Scatter(ArgsAction); // 1. r = (1, 2, 3).Scatter(ArgsFunc); // 2.
IV。将不同的args传递给采用元组的方法:
TupleAction.Gather(1, 2, 3); // 3. r = TupleFunc.Gather(1, 2, 3); // 4.
V.扩展方法Scatter
,Gather
在上文(III)和(IV)中使用:
// disperse n-tuple into Action arguments public static void Scatter(in this (T0 i0, T1 i1) t, Action a) => a(t.i0, t.i1); public static void Scatter (in this (T0 i0, T1 i1, T2 i2) t, Action a) => a(t.i0, t.i1, t.i2); public static void Scatter (in this (T0 i0, T1 i1, T2 i2, T3 i3) t, Action a) => a(t.i0, t.i1, t.i2, t.i3); // disperse n-tuple into Func arguments public static TResult Scatter (in this (T0 i0, T1 i1) t, Func f) => f(t.i0, t.i1); public static TResult Scatter (in this (T0 i0, T1 i1, T2 i2) t, Func f) => f(t.i0, t.i1, t.i2); public static TResult Scatter (in this (T0 i0, T1 i1, T2 i2, T3 i3) t, Func f) => f(t.i0, t.i1, t.i2, t.i3); // accumulate 'n' distinct args and pass into Action as an n-tuple public static void Gather (this Action<(T0, T1)> a, T0 i0, T1 i1) => a((i0, i1)); public static void Gather (this Action<(T0, T1, T2)> a, T0 i0, T1 i1, T2 i2) => a((i0, i1, i2)); public static void Gather (this Action<(T0, T1, T2, T3)> a, T0 i0, T1 i1, T2 i2, T3 i3) => a((i0, i1, i2, i3)); // accumulate 'n' distinct args and pass into Func as an n-tuple public static TResult Gather (this Func<(T0, T1), TResult> f, T0 i0, T1 i1) => f((i0, i1)); public static TResult Gather (this Func<(T0, T1, T2), TResult> f, T0 i0, T1 i1, T2 i2) => f((i0, i1, i2)); public static TResult Gather (this Func<(T0, T1, T2, T3), TResult> f, T0 i0, T1 i1, T2 i2, T3 i3) => f((i0, i1, i2, i3));
VI。奖金回合。如果您打算以其备用格式多次调用元组或与众不同的参数的委托,或者还没有准备好实际调用它,则可能希望从元组采用的形式显式地预先转换委托给等效的distingle-args委托,反之亦然。您可以缓存转换后的委托,以供以后多次重复使用。
var ga = ArgsAction.ToGathered(); // 1. // later... ga((1, 2, 3)); // ... ga((4, 5, 6)); var gf = ArgsFunc.ToGathered(); // 2. // later... r = gf((1, 2, 3)); // ... r = gf((4, 5, 6)); var sa = TupleAction.ToScattered(); // 3. // later... sa(1, 2, 3); // ... sa(4, 5, 6); var sf = TupleFunc.ToScattered(); // 4. // later... r = sf(1, 2, 3); // ... r = sf(4, 5, 6); // of course these approaches also supports in-situ usage: ArgsAction.ToGathered()((1, 2, 3)); // 1. r = ArgsFunc.ToGathered()((1, 2, 3)); // 2. TupleAction.ToScattered()(1, 2, 3); // 3. r = TupleFunc.ToScattered()(1, 2, 3); // 4.
七。VI中显示的奖金示例的扩展方法。
// convert tuple-taking Action delegate to distinct-args form public static ActionToScattered (this Action<(T0, T1)> a) => (i0, i1) => a((i0, i1)); public static Action ToScattered (this Action<(T0, T1, T2)> a) => (i0, i1, i2) => a((i0, i1, i2)); public static Action ToScattered (this Action<(T0, T1, T2, T3)> a) => (i0, i1, i2, i3) => a((i0, i1, i2, i3)); // convert tuple-taking Func delegate to its distinct-args form public static Func ToScattered (this Func<(T0, T1), TResult> f) => (i0, i1) => f((i0, i1)); public static Func ToScattered (this Func<(T0, T1, T2), TResult> f) => (i0, i1, i2) => f((i0, i1, i2)); public static Func ToScattered (this Func<(T0, T1, T2, T3), TResult> f) => (i0, i1, i2, i3) => f((i0, i1, i2, i3)); // convert distinct-args Action delegate to tuple-taking form public static Action<(T0, T1)> ToGathered (this Action a) => t => a(t.Item1, t.Item2); public static Action<(T0, T1, T2)> ToGathered (this Action a) => t => a(t.Item1, t.Item2, t.Item3); public static Action<(T0, T1, T2, T3)> ToGathered (this Action a) => t => a(t.Item1, t.Item2, t.Item3, t.Item4); // convert distinct-args Func delegate to its tuple-taking form public static Func<(T0, T1), TResult> ToGathered (this Func f) => t => f(t.Item1, t.Item2); public static Func<(T0, T1, T2), TResult> ToGathered (this Func f) => t => f(t.Item1, t.Item2, t.Item3); public static Func<(T0, T1, T2, T3), TResult> ToGathered (this Func f) => t => f(t.Item1, t.Item2, t.Item3, t.Item4);