题
我不明白何时应该使用输出参数,如果我需要返回多个类型,我个人会将结果包装在新类型中,我发现使用它比使用 out 更容易。
我见过这样的方法,
public void Do(int arg1, int arg2, out int result)
在某些情况下这实际上是有意义的吗?
怎么样 TryParse
, ,为什么不返回一个 ParseResult
类型?或者在较新的框架中返回一个可以为空的类型?
解决方案
Out是好当你有一个TryNNN
功能,很明显的是,从参数将始终,即使该函数没有成功设置。这可以让你依靠的事实,你声明的局部变量将被设置,而不是后来把支票在你对空代码。 (下面留言表示该参数可以设置为null
,所以你可能要验证你打电话,以确保如果是这种情况或不函数的文档)。这使得代码更清晰一点,更容易读书。另一种情况是,当你需要返回上的方法的条件的一些数据和一个状态,如:
public bool DoSomething(int arg1, out string result);
在这种情况下,返回可以指示如果函数成功且结果被存储在输出参数。诚然,这个例子是人为的,因为你可以设计一种在函数返回一个string
,但你的想法。
一个缺点是,必须声明一个局部变量来使用它们:
string result;
if (DoSomething(5, out result))
UpdateWithResult(result);
代替:
UpdateWithResult(DoSomething(5));
然而,这甚至可能不是一个缺点,它取决于你要去的设计。在日期时间的情况下,两个装置(解析和的TryParse)被提供。
其他提示
与大多数事情一样,这取决于情况。让我们看看选项
- 你可以返回任何你想要的作为函数的返回值
- 如果您想返回多个值或函数已经有返回值,您可以使用 out params 或创建一个新的复合类型,将所有这些值公开为属性
在 TryParse 的情况下,使用 out 参数是高效的 - 您不必创建一个新类型,这将是 16B 的开销(在 32b 机器上),也不必承担在调用后对它们进行垃圾收集的性能成本。例如,TryParse 可以从循环内调用 - 所以这里的参数规则。
对于不会在循环内调用的函数(即性能不是主要问题),返回单个复合对象可能会“更干净”(对观看者来说是主观的)。现在有匿名类型 和动态类型,它可能会变得更加容易。
笔记:
out
params 有一些需要遵循的规则,即编译器将确保函数在退出之前确实初始化该值。因此,即使解析操作失败,TryParse 也必须将输出参数设置为某个值- TryXXX 模式是何时使用参数的一个很好的例子 - Int32.TryParse 的引入是因为人们抱怨捕获异常以了解解析是否失败的性能。另外,如果解析成功,您最有可能做的事情是获取解析的值 - 使用输出参数意味着您不必对 Parse 进行另一个方法调用
我想出来是你需要同时返回一个布尔值和值,像的TryParse情况下非常有用,但它会是不错的,如果编译器会允许这样的事情:
bool isValid = int.TryParse("100", out int result = 0);
当然,当您有一种需要返回多个值的方法时,应使用 out 参数,在您发布的示例中:
public void Do(int arg1, int arg2, out int result)
使用 out 参数没有多大意义,因为您只返回一个值,如果删除 out 参数并放入 int 返回值,则可以更好地使用该方法:
public int Do(int arg1, int arg2)
out 参数有一些好处:
- 输出参数最初被视为未分配。
- 每个输出参数 必须 在方法返回之前明确分配,如果错过分配,您的代码将无法编译。
总之,我基本上尝试在我的 私有API 为了避免创建单独的类型来包装多个返回值,并且在我的公共 API 上,我仅在与 TryParse 模式匹配的方法上使用它们。
十年来,我知道。 出(和ref以及)也是非常有用的,如果你不希望你的方法做实例化一个新的对象返回。这是要实现你的方法亚微秒性能的高性能系统非常重要。实例化是相对昂贵看到从存储器存取的视角。
创建类型只是返回值听起来有点痛苦给我:-) 首先,我将不得不在调用方法我从返回类型需要它的实际变量赋值,然后返回值创建一个类型。
输出参数是simipler使用。
是的,这有一定道理。借此例如
String strNum = "-1";
Int32 outNum;
if (Int32.TryParse(strNum, out outNum)) {
// success
}
else {
// fail
}
你能返回如果操作与返回值的正常功能失败了吗?你肯定无法返回-1代表失败,因为那时会有故障返回值,这是被解析开始与实际值之间没有区别。这就是为什么我们返回一个布尔值,看它是否成功,如果它没有那么我们有我们的“回归”安全值已经分配。
它烦扰我,我不能在空传递给该功能的TryParse OUT参数。
不过,我喜欢它在某些情况下与两个数据返回一个新的类型。尤其是当他们是不相关的大部分或只需要片刻后单次操作一件。当我需要真正保存生成的一个函数的TryParse我的价值就像一出参数,而不是一些随机ResultAndValue类,我不得不处理。
如果你总是创建一个类型,那么你就可以在你的应用程序有很多杂乱的结束。
由于在这里说,一个典型的使用情况是要返回一个布尔值作为成功与否的指标,然后将实际值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);
}
至于“为什么不返回一个空类型”:自的TryParse框架1.x中存在,而空类型2.0来了(因为它们需要仿制药)。那么,为什么会不必要破坏兼容性或开始在某些类型的引入的TryParse之间的不一致?你总是可以编写自己的扩展方法来复制功能已经存在(见的上不相关的主题,其包括后面做一些推理埃里克Lipperts帖子 /不这样做的东西)
另一个用例是,如果你要返回多个不相关的值,即使如果你这样做应该触发报警,你的方法可能是做得太多。在另一方面,如果你的方法是像一个昂贵的数据库或Web服务调用,并要缓存的结果,它可能是有意义的做到这一点。当然,你可以创建一个类型,但同样,这意味着在应用程序中多了一个类型。
我使用的出有时为了可读性参数,读取方法名称时比任何方法的输出是-特别是对于执行除了命令来返回结果的方法更重要。
StatusInfo a, b, c;
Initialize(out a);
Validate(a, out b);
Process(b, out c);
VS
StatusInfo a = Initialize();
StatusInfo b = Validate(a);
StatusInfo c = Process(b);
至少对我来说,我把很多重点就当我在扫描每一行的前几个字符。我可以很容易地分辨承认,一些“StatusInfo”变量声明之后发生的事情在第一个例子。在第二个例子中,我看到的第一件事是一堆StatusInfo的检索。我必须扫描第二次看的方法可以有什么样的影响。