C#元组和值元组
C# 7.0已经出来⼀段时间了,⼤家都知道新特性⾥⾯有个对元组的优化:ValueTuple。这⾥利⽤详尽的例⼦详解Tuple VS ValueTuple(元组类VS值元组),10分钟让你更了解ValueTuple的好处和⽤法。
如果您对Tuple⾜够了解,可以直接跳过章节”回顾Tuple”,直达章节”ValueTuple详解”,查看值元组的炫丽⽤法。
回顾Tuple
Tuple是C# 4.0时出的新特性,.Net Framework 4.0以上版本可⽤。
元组是⼀种数据结构,具有特定数量和元素序列。⽐如设计⼀个三元组数据结构⽤于存储学⽣信息,⼀共包含三个元素,第⼀个是名字,第⼆个是年龄,第三个是⾝⾼。
元组的具体使⽤如下:
1.    如何创建元组
默认情况.Net Framework元组仅⽀持1到7个元组元素,如果有8个元素或者更多,需要使⽤Tuple的嵌套和Rest属性去实现。另外Tuple类提供创造元组对象的静态⽅法。
利⽤构造函数创建元组:
var testTuple6 = new Tuple<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}");
var testTuple10 = new Tuple<int, int, int, int, int, int, int, Tuple<int, int, int>>(1, 2, 3, 4, 5, 6, 7, new Tuple<int, int, int>(8, 9, 10));
Console.WriteLine($"Item 1: {testTuple10.Item1}, Item 10: {testTuple10.Rest.Item3}");
利⽤Tuple静态⽅法构建元组,最多⽀持⼋个元素:
var testTuple6 = Tuple.Create<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}");
var testTuple8 = Tuple.Create<int, int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7, 8);
Console.WriteLine($"Item 1: {testTuple8.Item1}, Item 8: {testTuple8.Rest.Item1}");
Note:这⾥构建出来的Tuple类型其实是Tuple<int, int, int, int, int, int, int, Tuple<int>>,因此testTuple8.Rest取到的数据类型是Tuple<int>,因此要想获取准确值需要取Item1属性。
2.    表⽰⼀组数据
如下创建⼀个元组表⽰⼀个学⽣的三个信息:名字、年龄和⾝⾼,⽽不⽤单独额外创建⼀个类。
var studentInfo = Tuple.Create<string, int, uint>("Bob", 28, 175);write的返回值
Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
3.    从⽅法返回多个值
当⼀个函数需要返回多个值的时候,⼀般情况下可以使⽤out参数,这⾥可以⽤元组代替out实现返回多个值。
static Tuple<string, int, uint> GetStudentInfo(string name)
{
return new Tuple<string, int, uint>("Bob", 28, 175);
}
static void RunTest()
{
var studentInfo = GetStudentInfo("Bob");
Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
}
4.    ⽤于单参数⽅法的多值传递
当函数参数仅是⼀个Object类型时,可以使⽤元组实现传递多个参数值。
static void WriteStudentInfo(Object student)
{
var studentInfo = student as Tuple<string, int, uint>;
Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
}
static void RunTest()
{
var t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(WriteStudentInfo));
t.Start(new Tuple<string, int, uint>("Bob", 28, 175));
while (t.IsAlive)
{
System.Threading.Thread.Sleep(50);
}
}
尽管元组有上述⽅便使⽤的⽅法,但是它也有明显的不⾜:
访问元素的时候只能通过ItemX去访问,使⽤前需要明确元素顺序,属性名字没有实际意义,不⽅便记忆;
最多有⼋个元素,要想更多只能通过最后⼀个元素进⾏嵌套扩展;
Tuple是⼀个引⽤类型,不像其它的简单类型⼀样是值类型,它在堆上分配空间,在CPU密集操作时可能有太多的创建和分配⼯作。因此在C# 7.0中引⼊了⼀个新的ValueTuple类型,详见下⾯章节。
ValueTuple详解
ValueTuple是C# 7.0的新特性之⼀,.Net Framework 4.7以上版本可⽤。
值元组也是⼀种数据结构,⽤于表⽰特定数量和元素序列,但是是和元组类不⼀样的,主要区别如下:
值元组是结构,是值类型,不是类,⽽元组(Tuple)是类,引⽤类型;
值元组元素是可变的,不是只读的,也就是说可以改变值元组中的元素值;
值元组的数据成员是字段不是属性。
值元组的具体使⽤如下:
1.    如何创建值元组
和元组类⼀样,.Net Framework值元组也只⽀持1到7个元组元素,如果有8个元素或者更多,需要使⽤值元组的嵌套和Rest属性去实现。另外ValueTuple类可以提供创造值元组对象的静态⽅法。
利⽤构造函数创建元组:
var testTuple6 = new ValueTuple<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}");
var testTuple10 = new ValueTuple<int, int, int, int, int, int, int, ValueTuple<int, int, int>>(1, 2, 3, 4, 5, 6, 7, new ValueTuple <int, int, int>(8, 9, 10));
Console.WriteLine($"Item 1: {testTuple10.Item1}, Item 10: {testTuple10.Rest.Item3}");
利⽤Tuple静态⽅法构建元组,最多⽀持⼋个元素:
var testTuple6 = ValueTuple.Create<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}");
var testTuple8 = ValueTuple.Create<int, int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7, 8);
Console.WriteLine($"Item 1: {testTuple8.Item1}, Item 8: {testTuple8.Rest.Item1}");
注意这⾥构建出来的Tuple类型其实是Tuple<int, int, int, int, int, int, int, Tuple<int>>,因此testTuple8.Rest取到的数据类型是Tuple<int>,因此要想获取准确值需要取Item1属性。
优化区别:当构造出超过7个元素以上的值元组后,可以使⽤接下来的ItemX进⾏访问嵌套元组中的值,对于上⾯的例⼦,要访问第⼗个元素,既可以通过testTuple10.Rest.Item3访问,也可以通过testTuple10.Item10来访问。
var testTuple10 = new ValueTuple<int, int, int, int, int, int, int, ValueTuple<int, int, int>>(1, 2, 3, 4, 5, 6, 7, new ValueTuple<int, int, int>(8, 9, 10));
Console.WriteLine($"Item 10: {testTuple10.Rest.Item3}, Item 10: {testTuple10.Item10}");
2.    表⽰⼀组数据
如下创建⼀个值元组表⽰⼀个学⽣的三个信息:名字、年龄和⾝⾼,⽽不⽤单独额外创建⼀个类。
var studentInfo = ValueTuple.Create<string, int, uint>("Bob", 28, 175);
Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
3.    从⽅法返回多个值
值元组也可以在函数定义中代替out参数返回多个值。
static ValueTuple<string, int, uint> GetStudentInfo(string name)
{
return new ValueTuple <string, int, uint>("Bob", 28, 175);
}
static void RunTest()
{
var studentInfo = GetStudentInfo("Bob");
Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
}
优化区别:返回值可以不明显指定ValueTuple,使⽤新语法(,,)代替,如(string, int, uint):
static (string, int, uint) GetStudentInfo1(string name)
{
return ("Bob", 28, 175);
}
static void RunTest1()
{
var studentInfo = GetStudentInfo1("Bob");
Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
}
调试查看studentInfo的类型就是ValueType三元组。
优化区别:返回值可以指定元素名字,⽅便理解记忆赋值和访问:
static (string name, int age, uint height) GetStudentInfo1(string name)
{
return ("Bob", 28, 175);
}
static void RunTest1()
{
var studentInfo = GetStudentInfo1("Bob");
Console.WriteLine($"Student Information: Name [{studentInfo.name}], Age [{studentInfo.age}], Height [{studentInfo.height}]");
}
⽅便记忆赋值:
⽅便访问:
4.    ⽤于单参数⽅法的多值传递
当函数参数仅是⼀个Object类型时,可以使⽤值元组实现传递多个值。
static void WriteStudentInfo(Object student)
{
var studentInfo = (ValueTuple<string, int, uint>)student;
Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
}
static void RunTest()
{
var t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(WriteStudentInfo));
t.Start(new ValueTuple<string, int, uint>("Bob", 28, 175));
while (t.IsAlive)
{
System.Threading.Thread.Sleep(50);
}
}
5.    解构ValueTuple
可以通过var (x, y)或者(var x, var y)来解析值元组元素构造局部变量,同时可以使⽤符号”_”来忽略不需要的元素。
static (string name, int age, uint height) GetStudentInfo1(string name)
{
return ("Bob", 28, 175);
}
static void RunTest1()
{
var (name, age, height) = GetStudentInfo1("Bob");
Console.WriteLine($"Student Information: Name [{name}], Age [{age}], Height [{height}]");
(var name1, var age1, var height1) = GetStudentInfo1("Bob");
Console.WriteLine($"Student Information: Name [{name1}], Age [{age1}], Height [{height1}]");
var (_, age2, _) = GetStudentInfo1("Bob");
Console.WriteLine($"Student Information: Age [{age2}]");
}
由上所述,ValueTuple使C#变得更简单易⽤。较Tuple相⽐主要好处如下:
ValueTuple⽀持函数返回值新语法”(,,)”,使代码更简单;
能够给元素命名,⽅便使⽤和记忆,这⾥需要注意虽然命名了,但是实际上value tuple没有定义这样名字的属性或者字段,真正的名字仍然是ItemX,所有的元素名字都只是设计和编译时⽤的,不是运⾏时⽤的(因此注意对该类型的序列化和反序列化操作);
可以使⽤解构⽅法更⽅便地使⽤部分或全部元组的元素;
值元组是值类型,使⽤起来⽐引⽤类型的元组效率⾼,并且值元组是有⽐较⽅法的,可以⽤于⽐较是否相等,详见:。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。