作者:陈广 日期:2018-6-1
之前在做文章发布系统的时候,遇到自定义函数要返回多个不同类型结果的情况,本来想使用 ref 参数解决,但突然发现 async 函数不支持 ref 参数。最后没办法,只能多写了一个类,把结果包装在类里返回,我只是想多返回一个结果,为此要多声明一个类,这让人感觉很不爽啊!其实写程序经常会遇到这样的情况,最后的结果就是你会发现项目里满天飞舞的类。那么有没有什么办法来替代这种简单的类声明呢?有的,早在 C#4.0 微软就推出了新特性:元组(Tuple),它就是用来解决此类问题的。
Tuple,是函数式编程的概念之一,早见于Elang、F#等动态语言。C# 4.0之前我们函数有多个返回值,通常是使用ref,out 。到了c# 4.0 应当使用元组Tuple而不是使用引用或输出参数。数组合并了相同类型的对象,而元组合并了不同类型的对象。
其实,我们也可以把元组理解为使用更为简单的类,不需要属性、构造函数、成员方法的类。我们先用类写一个例子并使用它,然后再将其更改为元组,看看两者有何区别。假设我们需要保存一个学生的学号和姓名信息,学号为整数,姓名为字符串,两个信息为不同类型。
表示这样的个学生信息的常规方法肯定是使用类:
class Student
{
public int ID { get; set; }
public string Name { get; set; }
public Student(int id, string name)
{
ID = id;
Name = name;
}
}
class Program
{
static void Main(string[] args)
{
Student stu = new Student(1, "张三");
Console.WriteLine($"学号:{stu.ID} 姓名:{stu.Name} ");
}
}
运行结果:
学号:1 姓名:张三
这还是新版本的写法,如果是老式写法,则需要声明两个私有成员变量,然后再写属性。
上面程序,如果使用元组,则变为:
static void Main(string[] args)
{
Tuple<int, string> stu = new Tuple<int, string>(1, "张三");
Console.WriteLine($"学号:{stu.Item1} 姓名:{stu.Item2} ");
}
我们看到,现在不再需要专门声明一个类来存放学生数据了,而是简单使用 Tuple 即可完成。方便不少!Item1
表示元组中的第一个参数,Item2
表示元组中的第二个参数。以上 Tuple 的声明还可以简化为:
var stu = new Tuple<int, string>(1, "张三");
也可以使用 Tuple 的静态方法Create
来创建元组:
var stu = Tuple.Create(1, "张三");
在C# 4.0中,Tuple 构造函数里的参数个数最多为8个。如果超过 8 个,只能在 Tuple 里嵌套另一个 Tuple 了。
C# 4.0中虽然实现了元组,使得我们写程序方便了许多,但总感觉哪看着不太顺眼,Item1
、Item2
、Item3
...。这也太难看了!如果在方法调用中作为返回值使用,你没办法明白这些返回项代表的是什么意思。之前使用类实现,stu.ID
一看就知道是学生学号,stu.Name
是学生姓名。直到C# 7.0,微软才对这个问题进行了改进。
C# 7.0 中,元组变帅了,而且变得很帅!它使用了System.ValueTuple
来代替System.Tuple
。我们用最新语法来更改上面的程序:
static void Main(string[] args)
{
var stu = (ID: 1, Name: "张三");
Console.WriteLine($"学号:{stu.ID} 姓名:{stu.Name} ");
}
现在再看程序,简洁,明了,长得越来越像 JavaScript 了。现在终于可以给每个成员起对应的名字了。我们观察到,两个成员并没有声明相应的类型,如果想限定成员的类型,可以这么写:
(int ID,string Name) stu = (1, "张三");
为了回答文章开头所提出的问题,我们还是专门写一个例子演示元组如何作为返回值使用吧。
static void Main(string[] args)
{
var stu = GetStudent();
Console.WriteLine($"学号:{stu.ID} 姓名:{stu.Name} ");
}
static (int ID, string Name) GetStudent()
{
return (1, "张三");
}
如果你希望将返回结果赋给两个变量,也可以这样写:
static void Main(string[] args)
{
(int id, string name) = GetStudent();
Console.WriteLine($"学号:{id} 姓名:{name} ");
}
static (int ID, string Name) GetStudent()
{
return (1, "张三");
}
还可以这样写:
(var id, var name) = GetStudent();
再简单点:
var (id, name) = GetStudent();
如果已经有现成的变量,还能写成这样:
int id;
string name;
(id, name) = GetStudent();
Console.WriteLine($"学号:{id} 姓名:{name} ");
元组可谓编程利器,它的出现,大大降低了程序的复杂度。使得我们可以更高效,简单地编写程序。元组可用于代替类,如果一个类满足以下条件,我们都可以考虑使用元组进行替代: