C#语言参考

元组

作者:陈广 日期: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中虽然实现了元组,使得我们写程序方便了许多,但总感觉哪看着不太顺眼,Item1Item2Item3...。这也太难看了!如果在方法调用中作为返回值使用,你没办法明白这些返回项代表的是什么意思。之前使用类实现,stu.ID一看就知道是学生学号,stu.Name是学生姓名。直到C# 7.0,微软才对这个问题进行了改进。

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} ");

总结

元组可谓编程利器,它的出现,大大降低了程序的复杂度。使得我们可以更高效,简单地编写程序。元组可用于代替类,如果一个类满足以下条件,我们都可以考虑使用元组进行替代:

  • 仅用于存放数据
  • 无需重载构造函数,并且构造函数中只是简单传值,没有其它逻辑处理
  • 类的属性中没有任何逻辑代码
  • 类中无成员方法
;

© 2018 - IOT小分队文章发布系统 v0.3