元组
析构元组
将var
关键字放在括号外,可使用 var
关键字,以便 C# 推断每个变量的类型。
var (name, address, city, zip) = contact.GetAddressInfo();
从 C# 10 开始,可在析构中混合使用变量声明和赋值。
public static void Main() { string city = "Raleigh"; int population = 458880; (city, population, double area) = QueryCityData("New York City"); // Do something with the data. }
析构用户定义类型
除了 record
和 DictionaryEntry 类型,C# 不提供析构非元组类型的内置支持。 但是,用户作为类、结构或接口的创建者,可通过实现一个或多个 Deconstruct
方法来析构该类型的实例。 该方法返回 void,且要析构的每个值由方法签名中的 out 参数指示
public void Deconstruct(out string fname, out string mname, out string lname)
DictionaryEntry类型提供 Deconstruct
方法。
Dictionary<string, int> snapshotCommitMap = new(StringComparer.OrdinalIgnoreCase) { ["https://github.com/dotnet/docs"] = 16_465, ["https://github.com/dotnet/runtime"] = 114_223, ["https://github.com/dotnet/installer"] = 22_436, ["https://github.com/dotnet/roslyn"] = 79_484, ["https://github.com/dotnet/aspnetcore"] = 48_386 }; foreach (var (repo, commitCount) in snapshotCommitMap) { Console.WriteLine( $"The {repo} repository had {commitCount:N0} commits as of November 10th, 2021."); }
使用扩展方法析构用户定义的类型
如果不是类的创建者,仍可通过实现一个或多个 Deconstruct
扩展方法来析构该类型的对象,以返回所需值。
public static void Deconstruct(this PropertyInfo p, out bool isStatic, out bool isReadOnly, out bool isIndexed, out Type propertyType) PropertyInfo prop = dateType.GetProperty("Now"); var (isStatic, isRO, isIndexed, propType) = prop;
推断元组元素名称
元组元素的名称可通过在初始化元组时使用的变量进行推断:
int count = 5; string label = "Colors used in the map"; var pair = (count, label); // element names are "count" and "label"
支持 ==
和 !=
两个元组具有相同数量的元素,且对于每个元组位置,可以使用 ==
和 !=
运算符对左右侧元组操作数中的相应元素进行比较
(int a, byte b) left = (5, 10); (long a, int b) right = (5, 10); Console.WriteLine(left == right); // output: True Console.WriteLine(left != right); // output: False var t1 = (A: 5, B: 10); var t2 = (B: 5, A: 10); Console.WriteLine(t1 == t2); // output: True Console.WriteLine(t1 != t2); // output: False
==
和 !=
操作不会考虑元组字段名称。
==
和 !=
运算符将以短路方式对元组进行比较。
在匿名类型和元组类型之间进行选择
“属性” | 访问修饰符 | 类型 | 自定义成员名称 | 析构支持 | 表达式树支持 |
---|---|---|---|---|---|
匿名类型 | internal |
class |
✔️ | ❌ | ✔️ |
Tuple | public |
class |
❌ | ❌ | ✔️ |
ValueTuple | public |
struct |
✔️ | ✔️ | ❌ |
在元组和匿名类型之间进行选择时,需要考虑几个因素。 一般来说,如果不使用表达式树,并且你熟悉元组语法,请选择 ValueTuple,因为它们提供可灵活命名属性的值类型。 如果使用表达式树并且想要命名属性,请选择匿名类型。
ValueTuple 类型是可变的,而 Tuple 是只读的。
Tips
使用元组来交换值,因此无需使用临时变量按顺序交换参数即可使用元组的重构
int[] c = { 0, 1 }; (c[1], c[0]) = (c[0], c[1]); Console.WriteLine(c[0] + " " + c[1]); // 1 0