Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C# 7 is it possible to deconstruct tuples as method arguments

Tags:

tuples

c#-7.0

For example I have

private void test(Action<ValueTuple<string, int>> fn) {     fn(("hello", 10)); }  test(t =>   {     var (s, i) = t;     Console.WriteLine(s);     Console.WriteLine(i); }); 

I would like to write something like this

private void test(Action<ValueTuple<string, int>> fn) {     fn(("hello", 10)); }  test((s,i) =>  {     Console.WriteLine(s);     Console.WriteLine(i); }); 

Is this possible with some proper notation?

like image 990
bradgonesurfing Avatar asked Jan 11 '17 11:01

bradgonesurfing


People also ask

What does |= mean in C?

The ' |= ' symbol is the bitwise OR assignment operator.

What is '~' in C programming?

In mathematics, the tilde often represents approximation, especially when used in duplicate, and is sometimes called the "equivalency sign." In regular expressions, the tilde is used as an operator in pattern matching, and in C programming, it is used as a bitwise operator representing a unary negation (i.e., "bitwise ...

What is an operator in C?

C operators are one of the features in C which has symbols that can be used to perform mathematical, relational, bitwise, conditional, or logical manipulations. The C programming language has a lot of built-in operators to perform various tasks as per the need of the program.

What is the use of in C?

In C/C++, the # sign marks preprocessor directives. If you're not familiar with the preprocessor, it works as part of the compilation process, handling includes, macros, and more.


2 Answers

You can shorten it to:

void test( Action<ValueTuple<string, int>> fn) {     fn(("hello", 10)); }  test(((string s, int i) t) => {     Console.WriteLine(t.s);     Console.WriteLine(t.i); }); 

Hopefully, one day we might be able to splat the parameters from a tuple to the method invocation:

void test(Action<ValueTuple<string, int>> fn) {     fn(@("hello", 10)); // <-- made up syntax }  test((s, i) => {     Console.WriteLine(s);     Console.WriteLine(i); }); 

But not at the moment.

like image 82
Paulo Morgado Avatar answered Nov 22 '22 21:11

Paulo Morgado


I. Examples of Action /Func delegates with distinct-args vs. single n-tuple arguments:

// 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. Demonstrate direct usage of the above examples

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. 

The examples in the next two sections invoke the delegates in their respective non-native argument forms. To delay the method call or to retain an adapted delegate for caching or delayed/multiple-call secenarios, see VI. and VII.

III. disperse ("splat") a tuple into multi-arg methods.

(1, 2, 3).Scatter(ArgsAction);      // 1.  r = (1, 2, 3).Scatter(ArgsFunc);    // 2. 

IV. pass distinct args into tuple-taking methods:

TupleAction.Gather(1, 2, 3);        // 3.  r = TupleFunc.Gather(1, 2, 3);      // 4. 

V. Extension methods Scatter and Gather used above in (III) and (IV):

// disperse n-tuple into Action arguments 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);  // disperse n-tuple into Func arguments 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);  // accumulate 'n' distinct args and pass into Action as an n-tuple 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));  // accumulate 'n' distinct args and pass into Func as an n-tuple 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. Bonus round. If you plan to call a tuple- or distinct-arg-taking delegate multiple times in its alternate form, or if you're not ready to actually invoke it yet, you may wish to explicitly pre-convert the delegate from tuple-taking form to the equivalent distinct-args delegate, or vice-versa. You can cache the converted delegate for multiple or arbitrary later re-use.

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. 

VII. Extension methods for bonus examples shown in VI.

// convert tuple-taking Action delegate to distinct-args form 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));  // convert tuple-taking Func delegate to its distinct-args form 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));  // convert distinct-args Action delegate to tuple-taking form 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);  // convert distinct-args Func delegate to its tuple-taking form 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); 
like image 32
Glenn Slayden Avatar answered Nov 22 '22 21:11

Glenn Slayden