Yuv*_*kov 184
是什么
ValueTuples以及为什么不Tuple呢?
A ValueTuple是反映元组的结构,与原始System.Tuple类相同.
Tuple和之间的主要区别ValueTuple是:
System.ValueTuple是一个值类型(struct),System.Tuple而是一个引用类型(class).在谈论分配和GC压力时,这很有意义.System.ValueTuple不仅是一个struct,它是一个可变的,并且在使用它们时必须要小心.想想当一个班级System.ValueTuple作为一个领域时会发生什么.System.ValueTuple 通过字段而不是属性公开其项目.直到C#7,使用元组不是很方便.他们的字段名称是Item1,Item2等等,并且语言没有为大多数其他语言提供语法糖(Python,Scala).
当.NET语言设计团队决定合并元组并在语言级别为它们添加语法糖时,一个重要因素是性能.随着ValueTuple是值类型,你可以使用它们,因为(作为一个实现细节)时,为了避免GC压力,他们会在栈上分配.
另外,struct运行时获取自动(浅)相等语义,而class不是.虽然设计团队确保元组的优化更加平等,但是为它实现了自定义相等.
以下是设计说明中Tuples的一段:
结构或类:
如上所述,我建议制作元组类型
structs而不是classes,因此不会将分配惩罚与它们相关联.它们应该尽可能轻.可以说,
structs最终会变得更加昂贵,因为作业会复制更大的价值.因此,如果他们的分配比创建的多得多,那么structs这将是一个糟糕的选择.然而,在他们的动机中,元组是短暂的.当零件比整体更重要时,你会使用它们.所以常见的模式是构造,返回并立即解构它们.在这种情况下,结构显然是可取的.
结构也有许多其他好处,这些好处将在下面变得明显.
你可以很容易地发现,使用它System.Tuple会很快变得模棱两可.例如,假设我们有一个计算a的总和和计数的方法List<Int>:
public Tuple<int, int> DoStuff(IEnumerable<int> values)
{
var sum = 0;
var count = 0;
foreach (var value in values) { sum += value; count++; }
return new Tuple(sum, count);
}
Run Code Online (Sandbox Code Playgroud)
在接收端,我们最终得到:
Tuple<int, int> result = DoStuff(Enumerable.Range(0, 10));
// What is Item1 and what is Item2?
// Which one is the sum and which is the count?
Console.WriteLine(result.Item1);
Console.WriteLine(result.Item2);
Run Code Online (Sandbox Code Playgroud)
您可以将值元组解构为命名参数的方式是该功能的真正强大之处:
public (int sum, int count) DoStuff(IEnumerable<int> values)
{
var res = (sum: 0, count: 0);
foreach (var value in values) { res.sum += value; res.count++; }
return res;
}
Run Code Online (Sandbox Code Playgroud)
并在接收端:
var result = DoStuff(Enumerable.Range(0, 10));
Console.WriteLine($"Sum: {result.Sum}, Count: {result.Count}");
Run Code Online (Sandbox Code Playgroud)
要么:
var (sum, count) = DoStuff(Enumerable.Range(0, 10));
Console.WriteLine($"Sum: {sum}, Count: {count}");
Run Code Online (Sandbox Code Playgroud)
如果我们查看前面示例的封面,我们可以确切地看到编译器ValueTuple在我们要求它解构时如何解释:
[return: TupleElementNames(new string[] {
"sum",
"count"
})]
public ValueTuple<int, int> DoStuff(IEnumerable<int> values)
{
ValueTuple<int, int> result;
result..ctor(0, 0);
foreach (int current in values)
{
result.Item1 += current;
result.Item2++;
}
return result;
}
public void Foo()
{
ValueTuple<int, int> expr_0E = this.DoStuff(Enumerable.Range(0, 10));
int item = expr_0E.Item1;
int arg_1A_0 = expr_0E.Item2;
}
Run Code Online (Sandbox Code Playgroud)
在内部,编译后的代码利用Item1和Item2,而是因为我们有一个元组分解工作,所有这一切都被抽象离我们越来越远.带有命名参数的元组用TupleElementNamesAttribute.注释.如果我们使用单个新变量而不是分解,我们得到:
public void Foo()
{
ValueTuple<int, int> valueTuple = this.DoStuff(Enumerable.Range(0, 10));
Console.WriteLine(string.Format("Sum: {0}, Count: {1})", valueTuple.Item1, valueTuple.Item2));
}
Run Code Online (Sandbox Code Playgroud)
注意,编译器仍然需要做一些魔术发生(通过属性),当我们调试我们的应用程序,因为这将是奇怪地看到Item1,Item2.
Abi*_*n47 21
Tuple和之间的区别ValueTuple是它Tuple是引用类型并且ValueTuple是值类型.后者是可取的,因为对C#7语言的更改使得元组被更频繁地使用,但是为每个元组在堆上分配新对象是一个性能问题,特别是当它不必要时.
但是,在C#7中,我们的想法是你永远不必显式使用任何一种类型,因为为元组使用添加了语法糖.例如,在C#6中,如果要使用元组返回值,则必须执行以下操作:
public Tuple<string, int> GetValues()
{
// ...
return new Tuple(stringVal, intVal);
}
var value = GetValues();
string s = value.Item1;
Run Code Online (Sandbox Code Playgroud)
但是,在C#7中,您可以使用:
public (string, int) GetValues()
{
// ...
return (stringVal, intVal);
}
var value = GetValues();
string s = value.Item1;
Run Code Online (Sandbox Code Playgroud)
您甚至可以更进一步,并给出值名称:
public (string S, int I) GetValues()
{
// ...
return (stringVal, intVal);
}
var value = GetValues();
string s = value.S;
Run Code Online (Sandbox Code Playgroud)
...或完全解构元组:
public (string S, int I) GetValues()
{
// ...
return (stringVal, intVal);
}
var (S, I) = GetValues();
string s = S;
Run Code Online (Sandbox Code Playgroud)
元组在C#pre-7中并不经常使用,因为它们既麻烦又冗长,而且只用于仅为单个工作实例构建数据类/结构的情况会比它的价值更麻烦.但是在C#7中,元组现在具有语言级支持,因此使用它们更清晰,更有用.
我看了看源都Tuple和ValueTuple.不同的是,Tuple是class和ValueTuple是一个struct实现IEquatable.
这意味着,Tuple == Tuple将返回false,如果他们是不一样的实例,但ValueTuple == ValueTuple将返回true如果它们是同一类型和Equals回报true每一个它们所包含的值.
其他答案忘记了要点。我将代替源代码,而是参考源代码中的XML文档:
ValueTuple类型(从0到8)在运行时实现中,它是C#中的元组的基础,而F#中的结构元组。
除了通过语言语法创建之外,还可以通过ValueTuple.Create工厂方法最轻松地创建它们
。该System.ValueTuple类型从不同System.Tuple在于类型:
通过引入这种类型和C#7.0编译器,您可以轻松编写
(int, string) idAndName = (1, "John");
Run Code Online (Sandbox Code Playgroud)
并从方法中返回两个值:
private (int, string) GetIdAndName()
{
//.....
return (id, name);
}
Run Code Online (Sandbox Code Playgroud)
相反,System.Tuple您可以更新其成员(可变),因为它们是公共读写字段,可以赋予有意义的名称:
(int id, string name) idAndName = (1, "John");
idAndName.name = "New Name";
Run Code Online (Sandbox Code Playgroud)
小智 6
除了上面的注释外,ValueTuple的不幸之处还在于,作为值类型,命名参数在编译为IL时会被擦除,因此它们在运行时不可用于序列化。
即,当您通过例如Json.NET进行序列化时,您的甜命名参数仍将最终以“ Item1”,“ Item2”等结尾。
| 归档时间: |
|
| 查看次数: |
35983 次 |
| 最近记录: |