C#中能否一行解构元组并传参?Pipe扩展优化方案问询
在C#里一行解构元组传参的实现方法
问题说明
场景1:直接把元组拆成方法参数
先看这段代码,现在得先把元组解构到变量才能传给DoSomethingWithStrings,我想直接用DoSomethingWithStrings(GetTuple())这种一行写法,不用中间变量:
public (string, string) GetTuple() { return ("a", "b"); } public string DoSomethingWithStrings(string str1, string str2) => str1 + str2; public void Example1() { var (a, b) = GetTuple(); var r = DoSomethingWithStrings(a, b); // 想让这行生效,但现在报错 //var r = DoSomethingWithStrings(GetTuple()); }
场景2:Pipe扩展方法支持解构式Lambda
我现在用Pipe的写法是Example2,想简化成Example3那样,直接在Pipe里用解构后的参数写Lambda,不用每次都写t.Item1、t.Item2:
// 当前的繁琐写法 public void Example2() { var t = GetTuple() .Pipe(t => DoSomethingWithStrings(t.Item1, t.Item2)); } // 想要的简化写法 public void Example3() { var t = GetTuple() .Pipe((a, b) => DoSomethingWithStrings(a, b)); }
目前我给Pipe写了二元组的重载,但如果是三元组、四元组还要再加,太麻烦了:
public static TResult Pipe<TInput, TResult>( this TInput input, Func<TInput, TResult> pipeFunc ) => pipeFunc(input); public static TResult Pipe<TInput1, TInput2, TResult>( this (TInput1, TInput2) input, Func<TInput1, TInput2, TResult> pipeFunc ) => input.Pipe(t => pipeFunc(t.Item1, t.Item2));
解决办法
1. 一行解构元组传参的实现
C#本身没直接支持把元组直接拆成方法参数的语法糖,但可以用这两种方式实现:
方法A:写个通用扩展方法适配
给二元组加个扩展方法,自动解构后调用目标方法:
public static TResult InvokeWith<T1, T2, TResult>(this (T1, T2) tuple, Func<T1, T2, TResult> func) { var (item1, item2) = tuple; return func(item1, item2); }
调用的时候就可以写成一行:
var r = GetTuple().InvokeWith(DoSomethingWithStrings);
方法B:用解构表达式凑成一行(可读性一般)
如果不想加扩展方法,也可以用C# 7.0+的解构语法写成一行,但可读性不如扩展方法:
var r = DoSomethingWithStrings((var a, var b) = GetTuple(), b);
2. 简化Pipe的重载问题
不用手动给每个元组长度写重载,有两种思路:
方式A:手动写常用长度的重载(够用就行)
常用的元组长度一般是2到7个,把这些长度的重载写完就够日常用了,每个重载里直接解构元组:
// 基础Pipe方法 public static TResult Pipe<TInput, TResult>(this TInput input, Func<TInput, TResult> pipeFunc) => pipeFunc(input); // 二元组 public static TResult Pipe<T1, T2, TResult>(this (T1, T2) input, Func<T1, T2, TResult> pipeFunc) { var (a, b) = input; return pipeFunc(a, b); } // 三元组 public static TResult Pipe<T1, T2, T3, TResult>(this (T1, T2, T3) input, Func<T1, T2, T3, TResult> pipeFunc) { var (a, b, c) = input; return pipeFunc(a, b, c); } // 四元组到七元组依此类推
这样Example3的写法直接就能用,不用再写t => ...这种冗余代码。
方式B:用源代码生成器自动生成重载
如果嫌手动写麻烦,可以用C#的源代码生成器,编译时自动给所有长度的ValueTuple生成对应的Pipe重载。核心就是遍历元组的泛型参数数量,自动生成代码,这样不用手动维护所有重载。
内容的提问来源于stack exchange,提问作者ChopSeo
相关产品推荐
相关产品推荐

