int a, b, n;
...
(a, b) = (2, 3);
// 'a' is now 2 and 'b' is now 3
这种事情在C#中真的很有帮助。在这个例子中,'a'和'b'没有被封装在一起,例如位置的X和Y可能是。这是否以某种形式存在?
以下是一个不太重要的例子。
(a, b) = n == 4 ? (2, 3) : (3, n % 2 == 0 ? 1 : 2);
Adam Maras在评论中表示:
var result = n == 4 ? Tuple.Create(2, 3) : Tuple.Create(3, n % 2 == 0 ? 1 : 2);
上述示例的工作类型,然后他指出它创建一个新的三元组而不是更改指定的值。
Eric Lippert要求用例,因此可能:
(a, b, c) = (c, a, b); // swap or reorder on one line
(x, y) = move((x, y), dist, heading);
byte (a, b, c, d, e) = (5, 4, 1, 3, 2);
graphics.(PreferredBackBufferWidth, PreferredBackBufferHeight) = 400;
notallama也有用例,他们在下面的回答中。
答案 0 :(得分:21)
我们已经考虑过支持元组的语法糖,但它没有成为C#4.0的标准。它不太可能成为C#5.0的标准; C#5.0团队非常忙于让异步/等待正常工作。我们将考虑该语言的假设未来版本。
如果您有一个非常可靠的用例,这将有助于我们确定该功能的优先级。
答案 1 :(得分:7)
用例:
使用IObservables非常好,因为它们只有一个类型参数。你基本上想要用任意委托订阅,但是你被迫使用Action,这意味着如果你想要多个参数,你必须使用元组,或者创建自定义类来打包和解包参数。
来自游戏的例子:
public IObservable<Tuple<GameObject, DamageInfo>> Damaged ...
void RegisterHitEffects() {
(from damaged in Damaged
where damaged.Item2.amount > threshold
select damaged.Item1)
.Subscribe(DoParticleEffect)
.AddToDisposables();
}
变为:
void RegisterHitEffects() {
(from (gameObject, damage) in Damaged
where damage.amount > threshold
select gameObject)
.Subscribe(DoParticleEffect)
.AddToDisposables();
}
我认为更清洁。
另外,当您想要传递多个值时,可能IAsyncResult会有类似的问题。有时创建类只是为了改变一些数据是很麻烦的,但是现在使用元组会降低代码的清晰度。如果它们在同一个函数中使用,匿名类型很适合该法案,但如果你需要在函数之间传递数据,它们就不起作用。
另外,如果糖也适用于通用参数,那就太好了。这样:
IEnumerator<(int, int)>
将desugar
IEnumerator<Tuple<int,int>>
答案 2 :(得分:3)
您正在寻找的行为可以在tuples具有支持或语法糖的语言中找到。 C#不属于这些语言;虽然你可以使用Tuple<...>
类来实现类似的行为,但它会非常冗长(不像你正在寻找的那样干净。)
答案 3 :(得分:1)
我能想到的最接近的结构是框架4.0版中的Tuple类。
答案 4 :(得分:1)
正如其他人已经写过的那样,C#4元组是一个很好的补充,但只要没有任何解包机制,就没有什么可以使用的。对于我使用的任何类型,我真正要求的是它所描述的内容的清晰度,在功能协议的两面(例如来电者,主叫方)......比如
Complex SolvePQ(double p, double q)
{
...
return new Complex(real, imag);
}
...
var solution = SolvePQ(...);
Console.WriteLine("{0} + {1}i", solution.Real, solution.Imaginary);
这在来电者和被叫者方面都很明显且清晰。不过这个
Tuple<double, double> SolvePQ(double p, double q)
{
...
return Tuple.Create(real, imag);
}
...
var solution = SolvePQ(...);
Console.WriteLine("{0} + {1}i", solution.Item1, solution.Item2);
在调用网站上,不会留下关于该解决方案实际是什么的正确线索(好的,字符串和方法名称使其非常明显)。 Item1和Item2属于同一类型,这使得工具提示无效。唯一可以确定的方法是通过SolvePQ
“反向工程”。
很明显,这是远远不够的,每个人都在进行严肃的数字化工作,应该有一个复杂的类型(就像在BCL中那样)。 但是每次获得拆分结果并且为了可读性而希望为这些结果提供不同的名称,您需要进行元组解包。重写的最后两行是:
var (real, imaginary) = SolvePQ(...); // or var real, imaginary = SolvePQ(...);
Console.WriteLine("{0} + {1}i", real, imaginary);
除了习惯语法之外,这没有留下混淆的余地。
答案 5 :(得分:1)
创建一组Unpack<T1, T2>(this Tuple<T1, T2>, out T1, out T2)
方法将是一种更为惯用的c#方式。
您的示例将成为
int a, b, n;
...
Tuple.Create(2, 3).Unpack(out a, out b);
// 'a' is now 2 and 'b' is now 3
这并不比你的建议复杂,而且更加清晰。
答案 6 :(得分:1)