使用 new 创建时命名 ValueTuple 属性

Name ValueTuple properties when creating with new

我知道我可以在隐式创建元组时命名参数,例如:

var me = (age: 21, favoriteFood: "Custard");

是否可以在显式创建元组时命名参数?即

var me = new ValueTuple<int, string>(21, "Custard");

我不这么认为。这是我在 ValueTuple 上找到的文档:

https://docs.microsoft.com/en-us/dotnet/api/system.valuetuple-7?view=netframework-4.7

我个人没有使用过ValueTuble类型。我以前像这样使用过元组 class:

var tuple = new Tuple<int, string>(21, "Custard");
var number = tuple.Item1;
var st = tuple.Item2;

但是我发现使用元组,尤其是当通过方法传递时,元组很笨重。总是必须知道 Item1 和 Item2 等中的内容。根据 ValueTuple 文档,它的使用方式相同。

你不应该只创建一个实体 class 吗?

我已经使用了我认为可以满足您需求的匿名类型。

var anyom = new
{
    age = 21,
    favoriteFood = "Custard"
};

number = anyom.age;
st = anyom.favoriteFood;

不,你不能。 ValueTuple 类型实际上独立于 C# 中的命名字段支持。后者更像是匿名类型的命名属性。也就是说,编译器分析代码并根据您的声明和用法为适当的成员生成别名。编译器通过赋值来学习字段的名称。由于基本构造函数语法不提供命名字段的机制,因此您不能使用它直接生成具有命名字段的元组。

当然,您可以通过多种方式重新解释从构造函数语法返回的值,从而为该返回值指定名称。我假设您知道这种方法并且正在寻找更直接的方法。

作为我所说 "re-interpret" 的示例,您可以这样做:

static (int value, string text) ConvertToNamed((int, string) t) => t;

然后这将在新变量中命名字段:

var t1 = new ValueTuple<int, string>(21, "hello");
var t2 = ConvertToNamed(t1);

变量 t1Item1Item2 卡住。但是编译器会隐式地为变量 t2.

生成所需的名称

也许更好的例子是您不需要额外的方法:

(int value, string text) t = new ValueTuple<int, string>(21, "hello");

同样,您并没有真正在构造函数语法中命名字段,但它们由局部变量声明重新解释。

这可能不是一个严重的限制。在希望有一个持久的、易于分配的名称的场景中,声明一个用户定义的类型可能比使用元组语法更好。您也可以为用户定义的类型编写解构函数,并且像这样声明类型意味着名称是第一个-class 公民在反射、dynamic 等方面

您可以在赋值期间强制转换为命名元组:

var me = ((int value, string text)) new ValueTuple<int, string>(21, "Custard");

... C# 7.0 doesn’t enable the use of custom item names when using the explicit System.ValueTuple<…> data type. Therefore, if you replace var in Example 8 of Figure 1, you’ll end up with warnings that each item name will be ignored.

Source

我发布这个答案是因为 docs 最接近的解释是:

Data members of ValueTuple types are fields. Data members of Tuple types are properties.

在 Linq 中使用 ValueTuple 时正在寻找这个。我做了一个 F2 重命名变量,它创建了以下语法:

var query = from x in myList
select (First: x.something, Second: x.other) into g
select new Whatever(g.First, g.Second);