C#使用ValueTuple优雅的返回多个值-程序旅途
图片来源:https://www.pexels.com

在开发的过程中经常遇到需要返回多个值的情况,有时候返回的值是一组相关的信息,比如,获取一个人的年龄和身高,通常应该定义一个类来接收返回的信息,但直接返回更方便。有时,一个方法可能只是校验是否符合条件,同时返回额外的信息。

Out关键字

我们在学习C#基础时,就已经知道了 out关键字。所以针对上面第二种情况可以使用out关键字来实现,如下面代码所示

static bool Check(out long timestamp)
{
    timestamp = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
    return true;
}

上面的代码只作为演示,没有实际意义。Check方法需要返回一个布尔值,同时需要接收内部返回的一个时间戳。

Tuple

上面的方法还可以使用Tuple来实现,代码如下

static Tuple<bool, long> Check()
{
    var timestamp = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
    return new Tuple<bool, long>(true, timestamp);
}

使用Tuple返回的结果,只能使用 Item1 , Item2 的形式访问,上面的例子中 Item1 代表检查结果,Item2 表示时间戳。从形式上来看不够优雅,而且使用Check方法时对返回的结果不易理解。

那么有没有好的办法呢?当然有,那就是ValueTuple。

ValueTuple

ValueTuple是在C# 7中引入的,它继承自 ValueType ,所以ValueTuple 是一个值类型,它的数据成员,如 Item1,Item2是字段而不是属性。使用ValueTuple实现上面的方法,如下:

static ValueTuple Check()
{
var timestamp = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
return new ValueTuple(true, timestamp);
}

这个跟使用Tuple一样,也是使用 Item1,Item2这样的形式获取结果。但是它有语法糖,也是优雅的地方。上面的方法还可以这样写

static (bool result, long timestamp) Check()
{
    var timestamp = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
    return (true, timestamp);
}

如下调用Check

var checkResult = Check();

Console.WriteLine(checkResult.result);
Console.WriteLine(checkResult.timestamp);

或者

(bool result, long timestamp) = Check();

Console.WriteLine(result);
Console.WriteLine(timestamp);

或者

var (result, timestamp) = Check();

Console.WriteLine(result);
Console.WriteLine(timestamp);

是不是很优雅。

结语

本篇文章通过简单的比较 out,Tuple 和 ValueTuple 的写法,展示了 ValueTuple的好处,并没有深入介绍。同时有一些地方,比如序列化时需要注意,这不在本篇讨论的范围,可以参考相关内容。