C#教程 - 元组与解构(Tuples and Deconstruction )
更新记录
转载请注明出处:
2022年9月24日 发布。
2022年9月10日 从笔记迁移到博客。
元组(tuples)说明
注意:C# 7.0可用
注意:元组不可以声明为静态类型
作用:元组常用于传递和返回多个值;匿名类型可以做的,Tuples基本都可以完成
元组是可变的(mutable),可以直接修改元组的成员
需要System. ValueType<T,T…>泛型类型支持
这个类型并非.NET Framework 4.6的一部分,4.7版本包含这个类型
注意:元组(Tuple)是值类型(value types),是可变类型(mutable (read/write))
tuple可以不定义元素名称,也可以定义命名Tuple元素(Naming Tuple Elements)
实例:
var bob = ("Bob", 23);
var joe = bob; // joe is a *copy* of bob
joe.Item1 = "Joe"; // Change joe's Item1 from Bob to Joe
Console.WriteLine (bob); // (Bob, 23)
Console.WriteLine (joe); // (Joe, 23)
定义元组
注意:命名元素后,仍然可以使用Item1这样的方式访问元素
注意:如果定义时,使用了外部的变量,可以直接使用.外部变量名方式访问
注意:tuple之间可以相互赋值,只要类型之间是兼容的
显式定义
实例:定义Tuple
var bob = ("Bob", 23); // Allow compiler to infer the element types
Console.WriteLine (bob.Item1); // Bob
Console.WriteLine (bob.Item2); // 23
实例:
//显式定义
(string name, int age, long code) panda1 = ("Panda1", 18, 666);
Console.WriteLine(panda1.name);
Console.WriteLine(panda1.age);
Console.WriteLine(panda1.code);
隐式定义
//隐式定义1
var panda2 = ("Panda2", 18, 888);
Console.WriteLine(panda2.Item1);
Console.WriteLine(panda2.Item2);
Console.WriteLine(panda2.Item3);
//隐式定义2(Naming Tuple Elements)
var panda3 = (name: "Panda3", age: 18, code: 666);
Console.WriteLine(panda3.name);
Console.WriteLine(panda3.age);
Console.WriteLine(panda3.code);
更多实例:
实例:
var tuple = (name:"Bob", age:23);
Console.WriteLine (tuple.name); // Bob
Console.WriteLine (tuple.age); // 23
实例:
static (string name, int age) GetPerson() => ("Bob", 23);
实例:
(string name, int age, char sex) bob1 = ("Bob", 23, 'M');
实例:定义Tuple(显式类型)
(string,int) bob = ("Bob", 23);
实例:定义tuple带元素命名
var tuple = (name:"Bob", age:23);
Console.WriteLine (tuple.name); // Bob
Console.WriteLine (tuple.age); // 23
实例:Tuple是值类型测试
var bob = ("Bob", 23); // Allow compiler to infer the element types
Console.WriteLine (bob.Item1); // Bob
Console.WriteLine (bob.Item2); // 23
var joe = bob; // joe is a *copy* of bob
joe.Item1 = "Joe"; // Change joe's Item1 from Bob to Joe
Console.WriteLine (bob); // (Bob, 23)
Console.WriteLine (joe); // (Joe, 23)
实例:直接使用外部变量名来访问
var now = DateTime.Now;
var tuple = (now.Day, now.Month, now.Year);
Console.WriteLine (tuple.Day); // OK
实例:方法返回tuple类型
static (string,int) GetPerson() => ("Bob", 23);
实例:方法返回tuple类型带命名
static (string name, int age) GetPerson() => ("Bob", 23);
var person = GetPerson();
Console.WriteLine (person.name); // Bob
Console.WriteLine (person.age); // 23
实例:tuple用在泛型类型中
Task<(string,int)>
Dictionary<(string,int),Uri>
IEnumerable<(int id, string name)> // See below for naming elements
实例:类型兼容的赋值
(string name, int age, char sex) bob1 = ("Bob", 23, 'M');
(string age, int sex, char name) bob2 = bob1; // No error!
元组作为返回值
简单元组返回值
using System;
using System.Runtime.Versioning;
namespace ConsoleApp1
{
class PandaClass
{
//实例
public (string,int) DoSomething()
{
return ("Panda", 666);
}
}
class Program
{
static void Main(string[] args)
{
PandaClass pandaClass = new PandaClass();
//测试
(string,int) result = pandaClass.DoSomething();
Console.WriteLine(result.Item1); //Panda
Console.WriteLine(result.Item2); //666
//wait
Console.ReadKey();
}
}
}
元组返回值 与 泛型 结合使用
using System;
using System.Collections.Generic;
using System.Runtime.Versioning;
namespace ConsoleApp1
{
class PandaClass
{
//实例
public List<(string, int)> DoSomething()
{
return new List<(string, int)> { ("Panda", 666) };
}
}
class Program
{
static void Main(string[] args)
{
PandaClass pandaClass = new PandaClass();
//测试
List<(string, int)> result = pandaClass.DoSomething();
Console.WriteLine(result.Count); //1
Console.WriteLine(result[0].Item1); //panda
Console.WriteLine(result[0].Item2); //666
//wait
Console.ReadKey();
}
}
}
元组返回值 与 成员命令
using System;
using System.Collections.Generic;
using System.Runtime.Versioning;
namespace ConsoleApp1
{
class PandaClass
{
//实例
public List<(string website, int code)> DoSomething()
{
return new List<(string, int)> { ("Panda", 666) };
}
}
class Program
{
static void Main(string[] args)
{
PandaClass pandaClass = new PandaClass();
//测试
List<(string website, int code)> result = pandaClass.DoSomething();
Console.WriteLine(result.Count); //1
Console.WriteLine(result[0].website); //panda
Console.WriteLine(result[0].code); //666
//wait
Console.ReadKey();
}
}
}
元组解构(Deconstructing Tuples)
Tuples implicitly support the deconstruction pattern
//显式解构
(string name, int age, int code) = ("Panda", 18, 666);
Console.WriteLine(name);
Console.WriteLine(age);
Console.WriteLine(code);
//隐式解构
(var name, var age, var code) = ("Panda", 18, 666);
Console.WriteLine(name);
Console.WriteLine(age);
Console.WriteLine(code);
//使用现有变量
string name;
int age;
int code;
(name, age, code) = ("Panda", 18, 666);
//省略不需要的数据(使用下划线代替即可)
(string name, _, int code) = ("Panda666", 18, 666);
Console.WriteLine(name);
Console.WriteLine(code);
实例:
var bob = ("Bob", 23);
(string name, int age) = bob;
Console.WriteLine (name);
Console.WriteLine (age);
实例:从方法返回值中解构
static (string, int, char) GetBob() => ( "Bob", 23, 'M');
static void Main()
{
var (name, age, sex) = GetBob();
Console.WriteLine (name); // Bob
Console.WriteLine (age); // 23
Console.WriteLine (sex); // M
}
元组的本质
匿名类型会在底层定义自定义类型
元组在底层使用预定义的System.ValueTuple<T,T…>泛型结构
public struct ValueTuple<T1>
public struct ValueTuple<T1,T2>
public struct ValueTuple<T1,T2,T3>
//...
每种ValueTuple都会定义Item1,Item2,...这样的属性
所以 (string,int) 是 ValueTuple<string,int>的别名
命名参数的Tuplue会在编译的时候,将自定义命名转为Item1,...这样的属性
比如:(string,int)在后台被转为 ValueTuple<string,int>
ValueTuple<string, int, int> s = ValueTuple.Create("Panda666", 18, 666);
Console.WriteLine(s.Item1);
Console.WriteLine(s.Item2);
Console.WriteLine(s.Item3);
有个例外是在方法返回命名Tuple时,会保留命名属性
底层使用TupleElementNamesAttribute特性来实现的
ValueTuple.Create
除了定义式声明Tuple,还可以使用Create工厂方法来创建Tuple
注意:这种方式无法定义命名的Tuple。因为命名Tuple是编译器实现的
实例:
ValueTuple<string,int> bob1 = ValueTuple.Create ("Bob", 23);
(string,int) bob2 = ValueTuple.Create ("Bob", 23);
元组的比较(Tuple Comparison)
ValueTuple在底层重写了Equal方法,可以直接使用,只要是成员顺序和值相同
ValueTuple<> overloads the == and != operators,从C# 7.3开始
元组还实现了IComparable接口,所以可以作为排序的键
ValueTuple<> also implement IComparable
实例:
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var panda1 = ("Panda666.com",666);
var panda2 = ("Panda666.com",666);
Console.WriteLine(panda1 == panda2); //true
Console.WriteLine(panda1.Equals(panda2)); //true
//wait
Console.ReadKey();
}
}
}
实例:
var t1 = ("one", 1);
var t2 = ("one", 1);
Console.WriteLine (t1 == t2); // True (from C# 7.3)
Console.WriteLine (t1.Equals (t2)); // True
实例:使用Equals方法
var t1 = ("one", 1);
var t2 = ("one", 1);
Console.WriteLine (t1.Equals (t2)); // True
Console.WriteLine (t1 == t2); // 使用==运算符,True
元组与System.Tuple类型
Tuple在.NET Framework 4.0中引入
System.Tuple是一个类,而System.ValueType是一个泛型结构
Tuple没有C#语言支持,而元组有
优先考虑使用ValueTuple
实例:
Tuple<string,int> t = Tuple.Create ("Bob", 23); // Factory method
Console.WriteLine (t.Item1); // Bob
Console.WriteLine (t.Item2); // 23
Tuple实例:
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Tuple<string, int> tuple1 = new Tuple<string, int>("Panda", 666);
Tuple<string, int> tuple2 = Tuple.Create("Panda", 666);
Console.WriteLine(tuple1.Item1); //Panda
Console.WriteLine(tuple1.Item2); //666
Console.WriteLine(tuple2.Item1); //Panda
Console.WriteLine(tuple2.Item2); //666
//wait
Console.ReadKey();
}
}
}
本文来自博客园,作者:重庆熊猫,转载请注明原文链接:https://www.cnblogs.com/cqpanda/p/16715163.html