对使用多返回值的一点看法

背景

    近期维护的一个项目(基于.net framework 4.0)中,看到了不少使用out关键字来返回多个返回值的方法,方法的签名很长很长,

没用out关键字标识的参数就一两个,用out关键字标识的参数却有三四个。

对于多返回值,不同的人可能会有不同的看法:

  • 有的人可能会认为多返回值根本就不应该存在,一个方法应该最多有一个返回值就够了,多了可能就是设计什么的有问题
  • 有的人可能会认为多返回值很有存在的意义,因为多返回值很灵活,能适应更多不同场景的设计和业务

简单的例子

虚拟场景:现在要写一个方法,这个方法做的事是计算两个数加减乘除的结果。

用out的做法就是将计算的4个结果,通过用out标识的参数传出去。示例如下:

private static void GetResult(int num1, int num2,out int add,out int multi,out int sub, out int div)
{
    add = num1 + num2;
    multi = num1 * num2;
    sub = num1 - num2;
    div = num2 == 0 ? 0 : num1 / num2;
}

在调用之前,我们需要先定义4个变量用于接收调用方法要传出来的4个计算结果,示例如下:

int num1 = 2;
int num2 = 3;
int add, multi, sub, div;
GetResult(num1, num2, out add, out multi, out sub, out div);
Console.WriteLine($"add={add};multi={multi};sub={sub};div={div}");

输出结果如下:

add=5;multi=6;sub=-1;div=0

    这样的做法是能完成我们定义的场景,但是,一个方法有6个参数,是否有点不尽人意呢?如果没点注释或命名不好,估计这几个参数用来

做什么的都没人知道,重要的是如果方法很长很长,不能一眼就看到这些参数的话,估计就会感觉有点迷糊。

在C#4中,有一个新特性 Tuple 很适合用来返回多个结果,下面来看看针对这个场景的实现:

private static Tuple<int, int, int, int> GetResultWithTuple(int num1, int num2)
{
    int add = num1 + num2;
    int multi = num1 * num2;
    int sub = num1 - num2;
    int div = num2 == 0 ? 0 : num1 / num2;
    return Tuple.Create<int, int, int, int>(add,multi,sub,div);
}

调用比较简单,像一般方法一样,定义一个变量去接收方法返回的结果即可。不同的是,这个结果包含了多个值,就像一个类有多个属性那样。

int num1 = 2;
int num2 = 3;
var res = GetResultWithTuple(num1, num2);
Console.WriteLine($"add={res.Item1};multi={res.Item2};sub={res.Item3};div={res.Item4}");

输出结果和上面使用out的方法是一致的。

用这种方法来处理的好处是无论方法内部还是调用都是很简洁,唯一的缺点就是Item1~Item4,不能见名知意,尤其是不熟悉Tuple这一类型的。

说到多返回值(Tuple),就不得不提Python了,因为Python中也有相似的东西,同样的例子,看看Python中如何实现:

def getResult(num1,num2):
    add = num1+num2;
    multi = num1*num2;
    sub = num1-num2;
    div = num1/num2 if num2!=0 else 0;
    return add,multi,sub,div;

调用如下:

add,multi,sub,div = getResult(2,3);    
print(type(getResult(1,2)));
print('add={};multi={};sub={};div={};'.format(add,multi,sub,div))

输出如下:

<class 'tuple'>
add=5;multi=6;sub=-1;div=0.6666666666666666;    

在调用的时候,特地输出了getResult的类型(tuple),这个类型和C#中的Tuple是一样的,都是创建的时候就定死了内容,后面不能修改的。

看起来,似乎Python用起来更加简单哈。

不得不说的是,在最新的C# 7.0中,也已经有了基于Tuple的多返回值方法,用法和Python的类似,可以说是一样的了,具体内容如下:

What’s New in C# 7.0

总结

    处理多返回值的方法远不止只有out和Tuple两种,有人会用Dictionary来处理,有人会封装一个类来处理,有人会用dynamic来处理...

但是我个人是更倾向于用Tuple来处理多返回值,虽然感觉ItemX不那么友好,但是除了这点,其他方面还是很好用、很不错的。不用为了

一个方法特地去定制一个类做为返回值。更重要的是在7.0的语法中,也是用基于Tuple的实现,所以我又有什么理由不用呢?

    当然要用Tuple也是有个大前提的,那就是.net framework 必须是要4.0或更高的版本,3.5及更低的版本就只能用其他的办法了。

    最后,就顺手将项目中使用了out关键字的部分方法重构成了用Tuple作为返回值,让这些方法有了更高的可读性和简洁性!!

posted @ 2016-12-25 12:37 Catcher8 阅读(...) 评论(...) 编辑 收藏