我不理解何时应该使用输出参数,如果我需要返回多个类型的结果,我会将其包裹在一个新的类型中,我发现这比 out 更容易处理。
我看到过像这样的方法:
public void Do(int arg1, int arg2, out int result)
是否有任何情况下实际上这样做是有意义的?
TryParse
呢?为什么不返回一个ParseResult
类型呢?或者在较新的框架中返回可空类型呢?
我不理解何时应该使用输出参数,如果我需要返回多个类型的结果,我会将其包裹在一个新的类型中,我发现这比 out 更容易处理。
我看到过像这样的方法:
public void Do(int arg1, int arg2, out int result)
是否有任何情况下实际上这样做是有意义的?
TryParse
呢?为什么不返回一个ParseResult
类型呢?或者在较新的框架中返回可空类型呢?
如果你有一个名为TryNNN
的函数,并且明确了即使该函数不成功,输出参数也将始终被设置,那么使用 out 关键字是很好的选择。这允许你信赖你声明的局部变量将被设置,而不必在代码后面放置对 null 的检查(下面的评论指出该参数可能会被设置为null
,因此你可能需要验证你调用的函数的文档是否确实如此)。它使代码更清晰易读。另一种情况是当你需要返回一些数据以及方法条件的状态时:
public bool DoSomething(int arg1, out string result);
在这种情况下,返回值可以表明函数是否成功,并且结果存储在输出参数中。诚然,这个例子有些牵强,因为你可以设计一种方式,使函数简单地返回一个字符串,但是你可以理解这个想法。string result;
if (DoSomething(5, out result))
UpdateWithResult(result);
改为:
UpdateWithResult(DoSomething(5));
不过,这甚至可能不是一个缺点,这取决于你想要的设计。在 DateTime 的情况下,提供了两种方法(Parse 和 TryParse)。
if (DoSomething(5, out var result)) { ... }
。 - snowflake 我知道回答晚了好几年。 如果您不希望您的方法实例化一个新对象返回,则out(和ref)也非常有用。这在高性能系统中非常重要,因为您希望方法的性能达到亚微秒级别。从内存访问的角度来看,实例化相对昂贵。
好的,就像大多数事情一样,这取决于情况。 让我们看看选择:
对于 TryParse,使用 out 参数是高效的——您不需要创建一个新类型,这会产生 16B 的开销(在 32b 机器上)或者在调用后承担它们垃圾回收的性能成本。例如,TryParse 可以从循环内部调用——因此,在这里 out 参数统治。
对于那些不会在循环内部调用的函数(即性能不是主要关注点),返回单个复合对象可能会更加“干净”(这取决于观察者的主观判断)。现在有匿名类型和动态类型,这使得它甚至变得更容易了。
注意:
out
参数有一些需要遵循的规则,即编译器将确保函数在退出之前初始化该值。因此,TryParse 必须将 out 参数设置为某个值,即使解析操作失败。我认为out关键字在需要返回布尔值和数值的情况下很有用,比如TryParse方法。但是如果编译器允许以下代码就更好了:
bool isValid = int.TryParse("100", out int result = 0);
当你需要一个方法返回多个值时,out参数就是为此而设计的,在你所发布的示例中就是这种情况:
public void Do(int arg1, int arg2, out int result)
使用输出参数并不是很有意义,因为您只返回一个值,如果删除输出参数并将其替换为 int 返回值,则可以更好地使用该方法:
public int Do(int arg1, int arg2)
关于out参数,有一些好处:
总的来说,在我的私有API中,我基本上尝试使用out参数来避免创建包含多个返回值的单独类型,在我的公共API中,我只在与TryParse模式匹配的方法中使用它们。
是的,这是有道理的。以这个为例。
String strNum = "-1";
Int32 outNum;
if (Int32.TryParse(strNum, out outNum)) {
// success
}
else {
// fail
}
如果您总是创建一个类型,那么您的应用程序中可能会有很多混乱。
正如在这里所说,一个典型的用例是一个TrySomething
方法,您希望返回一个布尔值作为成功的指示器,然后是实际值。我也发现在if语句中更加清晰 - 所有三个选项大致具有相同的LOC。
int myoutvalue;
if(int.TryParse("213",out myoutvalue){
DoSomethingWith(myoutvalue);
}
vs.
ParseResult<int> myoutvalue = int.TryParse("213");
if ( myoutvalue.Success ) {
DoSomethingWith(myoutvalue.Value);
}
vs.
int? myoutvalue = int.TryParse("213");
if(myoutvalue.HasValue){
DoSomethingWith(myoutvalue.Value);
}
专门为返回值创建一个类型对我来说有点痛苦 :-) 首先,我必须创建一个用于返回值的类型,然后在调用方法中,我必须将返回类型中的值分配给需要它的实际变量。
输出参数使用起来更简单。
我很烦恼的是,我不能将null传递给TryParse函数的out参数。
尽管如此,在某些情况下,我更喜欢它返回一个具有两个数据部分的新类型。特别是当它们大多数情况下不相关或其中一个部分仅在一段时间后需要进行单个操作时。当我确实需要保存TryParse函数的结果值时,我真的很喜欢使用out参数,而不是一些随机的ResultAndValue类来处理。
StatusInfo a, b, c;
Initialize(out a);
Validate(a, out b);
Process(b, out c);
对比
StatusInfo a = Initialize();
StatusInfo b = Validate(a);
StatusInfo c = Process(b);