问题描述
返回多个双精度值的方法可以通过多种方式实现:
通过 out
参数:
class MyClass
{
static double Add3(double x,out double xp1,out double xp2)
{
xp1 = x + 1.0;
xp2 = x + 2.0;
return x + 3.0;
}
}
通过元组:
class MyClass
{
static Tuple<double,double,double> Add3(double x)
{
Tuple<double,double> ret = new Tuple<double,double>();
ret.Item1 = x + 1.0;
ret.Item2 = x + 2.0;
ret.Item3 = x + 3.0;
return ret;
}
通过一个班级收集结果:
class MyClass
{
class Result
{
double xp1;
double xp2;
double xp3;
}
static Result Add3(double x)
{
Result ret = new Result
{
xp1 = x + 1.0;
xp2 = x + 2.0;
xp3 = x + 3.0;
}
return ret;
}
}
我对 this question 的评论给我的印象是,人们通常认为加班的方法是最佳做法。但是,我想知道是否存在关于三种变体对运行时性能影响的经验法则。
与 Tuple
参数相比,out
或类的构造函数是否需要额外的时间?
特别是,在实际只使用一个结果双精度值的情况下,带有 out
参数的变体是否有任何性能优势,例如在以下代码段中?
double zPlus3 = MyClass.Add3(z,out _,out _)
解决方法
通过 Tuple<T1,T2,T3>
或具有 3 个属性的自定义类返回多个值,在性能方面是等效的。元组更容易获得(您不必对它们进行编码),而自定义类使用起来更方便,但这两种方法都涉及引用类型的实例化,必须进行堆分配,然后进行垃圾回收。如果您仅将这些类型用于访问它们的属性一次,那么您将无法获得额外的价值来补偿堆分配/垃圾收集开销。在这种情况下,使用 out
参数在性能方面更胜一筹。不过,还有第四种解决方案,它结合了所有这些方法的优点:value tuples(在 C# 7.0 及更高版本中可用)。
static (double,double,double) Add3(double x)
{
return (x + 1.0,x + 2.0,x + 3.0);
}
使用示例,演示tuple deconstruction:
(double xp1,double xp2,double xp3) = Add3(13);
...或等效地使用类型推断:
var (xp1,xp2,xp3) = Add3(13);
优点:
-
ValueTuple<T1,T3>
与Tuple<T1,T3>
一样容易获得。 - 对
ValueTuple<T1,T3>
的 changing the field names 的语言支持比Item1
、Item2
和Item3
更有意义,使它们(几乎)同样方便到自定义类。 - 一个
ValueTuple<T1,T3>
存储在堆栈中,就像out
参数一样。不涉及堆分配和垃圾收集。