【问题标题】:How to create named reference-type tuples?如何创建命名的引用类型元组?
【发布时间】:2017-11-13 07:41:09
【问题描述】:

以下行创建了一个名为ValueTuple

var tuple = (a:1, b:2, c:3, d:4, e:5, f:6);  

值类型不能有效地传递。 C#7 是否提供了一种创建 Tuple 类型的命名元组的方法?

【问题讨论】:

  • 不,这是两种不同的类型
  • 你打算如何使用这些元组?您不能普遍地声称效率高于另一个...这取决于您如何使用它。
  • 补充@JeffMercado 所说的,考虑到引用类型会导致 GC 惩罚,因此根据情况,有时复制值类型结构比造成大量 GC 压力要快。发生这种情况的一种特殊情况是,如果您以高频率创建和“忘记”对象,这样 GC 由于分配压力而不得不不断运行。在这些情况下,您付出的性能损失有时可能比一系列值类型副本更糟糕。不过,只有分析员才能确定地告诉您。
  • @ ozeanix 我理解 ValueTuple 的原因 - 经常创建,使用一次 - 但大多数时候您只想将元组用作简单的容器,语法方便,例如作为数据包在类属性中public (int a, int b) Data;
  • 那么你选择Tuple 而不是ValueTuple 是没有用的。首先使用该语言为您提供的内容,直到您确定可以从使用Tuple 中受益。从您在此处显示的内容来看,您并不知道。

标签: c# tuples named reference-type c#-7.0


【解决方案1】:

不确定是什么问题;对于我来说,一切都按预期进行,因为通过 outref 和新的 ref locals 传递了新的 ValueTuple<T>

我正在使用 .NET 4.7 并在 .csproj 设置“高级...”按钮中将我的 C#7 编译器设置为“最新”。

演示函数(和数据):

static (int, int) g = (1, 2);

static void SetValues(int a, int b, ref (int, int) tt) => tt = (a, b);

static void SetValuesOut(int a, int b, out (int, int) tt) => tt = (a, b);

static ref (int, int) GetKnownTuple() => ref g;

static ref (int, int) SelectRef(
    int ix, 
    ref (int, int) x, 
    ref (int, int) y, 
    ref (int, int) z)
{
    if (ix == 0) return ref x;
    if (ix == 1) return ref y;
    return ref z;
}

用法示例:

static void demo_usages() {

/// use 'ref return' to initialize a new 'ref local' tuple 'aa'
ref (int, int) aa = ref GetKnownTuple();

/// or use the same function without 'ref' to create a local COPY 'bb'
var bb = GetKnownTuple();

/// use 'ref' parameter to modify values of local copy 'bb' ('aa/g' are not altered)
SetValues(3, 4, ref bb);

/// deconstruction of 'ref local' tuple; reads values from referent 'g' (1, 2)
(int x, int y) = aa;

/// 'ref local' reference to a local tuple copy
ref (int, int) dd = ref bb;

/// use 'out' parameter to construct a new (non-'ref') local tuple 'cc'
SetValuesOut(y, x, out (int, int) cc);

/// ...or use 'out' with 'ref local' to wholly replace existing referent ('g' here)
SetValuesOut(5, 6, out aa);

/// 'ref return' function can also be used as assignment l-value...
GetKnownTuple() = (7, 8);

/// ('aa/g' are altered; locals 'bb' and 'cc' remain unchanged)

/// ...or assign a referent via 'ref local' variable (changes 'g' again)
aa = (9, 10);

/// conditional assignment via 'ref return'  (changes 'g' again)
SelectRef(0, ref aa, ref bb, ref cc) = (11, 12);

}

应该清楚,还有更多可能,但这里不能全部显示,因为 OP 的问题没有涉及太多具体的进一步要求。

【讨论】:

  • 这个解释很详细,很有帮助,谢谢
  • 你没有回答这个问题,那只是胡言乱语。
【解决方案2】:

如果您的意思是如果有办法将其他名称附加到 System.Tuple<...> 实例的属性,那么没有。

根据您想要它的原因,您可以通过使用TupleExtensions 中的ToValueTuple 重载将System.Tuple<...> 实例转换为System.ValueTuple<...> 实例并使用ToTuple 重载返回来绕过它。

如果您真的不需要元组,可以使用Deconstruct 重载或var (v1, .., vn) = tuple 解构语法将它们解构为离散变量。

【讨论】:

  • 元组有属性Itemn,命名元组是,好吧,命名。实现起来并不容易
  • 是的,@Brandon,它很容易实现,而且不为元组引入新类型会更容易。所以看起来。但如果你有这种感觉,那么你很可能做错了。
猜你喜欢
  • 2017-07-02
  • 2019-05-22
  • 2017-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-20
  • 1970-01-01
  • 2018-01-14
相关资源
最近更新 更多