正在使用“out”不好的做法
我刚刚在我编写的方法中添加了一个 out bool 参数,以便在我的 UI 中收到警告。我使用了 out 而不是让方法本身返回 false/true,因为这意味着 DoSomething 失败/成功。我的想法是 warnUser 将指示警告实际上是什么,而不必查看该方法的实现。
原始代码
public void DoSomething(int id, string input);
新代码
public void DoSomething(int id, string input, out bool warnUser);
我正在使用 Moq 来测试此代码,但它不支持 out/ref 参数,因为 Lambda 表达式不支持它们
测试代码
mockService.Verify(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<bool>());
那么,使用 out 参数是不好的做法吗?如果是,我该怎么办?
I have just added an out bool parameter to a method I've written in order to get a warning in to my UI. I've used an out rather than getting the method itself to return false/true as that would imply the DoSomething failed/succeeded. My thinking was that the warnUser would indicate what the warning actually was without having to look at the implementation of the method.
Original Code
public void DoSomething(int id, string input);
New Code
public void DoSomething(int id, string input, out bool warnUser);
I'm using Moq to test this code, but it doesn't support out/ref parameters because they're not supported by Lambda expressions
Test Code
mockService.Verify(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<bool>());
So, is using out parameters bad practise and if so what do I do instead?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
在 void 方法中使用 out 参数通常是一个坏主意。你说你已经使用它“而不是让方法本身返回 false/true,因为这意味着 DoSomething 失败/成功” - 我不相信存在这种暗示。通常在 .NET 中,失败是通过异常而不是真/假来指示的。
out
参数通常比返回值使用起来更难看 - 特别是,您必须有一个正确类型的变量来处理,因此您不能只写:您可能需要考虑的一种替代方法是指示所需警告级别的枚举。例如:
然后该方法可以返回
WarningLevel
而不是bool
。这会让你的意思更清楚——尽管你可能想稍微重命名一些东西。 (很难用诸如“DoSomething”之类的元语法名称提供建议,尽管我完全理解您为什么在这里使用它。)当然,另一种选择是您可能希望提供更多信息 - 就像原因< /em> 作为警告。这可以通过枚举来完成,或者您可能想完全给出一些更丰富的结果。
Using an out parameter in a void method is generally a bad idea. You say you've used it "rather than getting the method itself to return false/true as that would imply the DoSomething failed/succeeded" - I don't believe that implication is there. Usually in .NET failure is indicated via an exception rather than true/false.
out
parameters are generally uglier to use than return values - in particular, you have to have a variable of the right type to handle, so you can't just write:One alternative you might want to consider is an enum indicating the warning level required. For example:
Then the method could return a
WarningLevel
instead ofbool
. That would make it clearer what you meant - although you might want to rename things slightly. (It's hard to give advice with metasyntactic names such as "DoSomething" although I entirely understand why you've used that here.)Of course, another alternative is that you might want more information to be present - like the reason for the warning. That could be done with an enum, or you might want to give some richer result entirely.
out
是非常一个有用的构造,特别在像bool TryGetFoo(..., out value)
这样的模式中>,您想分别了解“如果”和“什么”(可为空不一定是一个选项)。然而 - 在这种情况下,为什么不直接做到:
并使用返回值来表示这一点?
out
is very much a useful construct, in particular in patterns likebool TryGetFoo(..., out value)
, where you want to know the "if" and the "what" separately (and nullable isn't necessarily an option).However - in this case, why not just make it:
and use the return value to signal this?
一些额外的想法:
FxCop 所说的:CA1021:避免输出参数< /a>
对于私有/内部方法(实现细节)
out
/ref
参数不是一个问题C# 7 元组 通常是
out
参数的更好替代品此外,C# 7 通过引入“out 变量”并允许“丢弃”,改进了调用站点上
out
参数的处理out
参数A few additional thoughts:
What FxCop says: CA1021: Avoid out parameters
For private/internal methods (implementation details)
out
/ref
parameters are less of an issueC# 7 Tuples often are a better alternative to
out
parametersFurther, C# 7 improves the handling of
out
parameter on the call site by introducing "out variables" and by allowing to "discard"out
parameters给定一个大的遗留代码方法(例如 15 行以上,200 行以上的遗留代码方法很常见),人们可能希望使用“提取方法”重构来清理并使代码更不易损坏且更易于维护。
这种重构很可能产生一个或多个新方法,而没有用于设置先前方法本地变量值的参数。
就我个人而言,我使用这种情况作为一个强有力的指标,表明在先前的方法中隐藏了一个或多个离散类,以便我可以使用“提取类”,在新类中,这些输出参数获取对调用可见的属性(先前)方法。
我认为在先前的方法中留下不带参数的提取方法是不好的做法,跳过“提取类”的连贯的后续步骤,因为如果跳过它,这些局部变量仍保留在先前的函数中,但在语义上不再属于到它。
因此,在这种情况下,我认为 out 参数是破坏 SRP 的代码味道。
Given a big Legacy Code Method (say 15+ lines, legacy code methods with 200+ lines are quite common), one might want to use the "Extract Method" refactoring to clean up and make code less brittle and more maintainable.
Such a refactoring is very likely to produce one or more new methods with out parameters for setting variable values local to the prior method.
Personally, I use this circumstance for a strong indicator that there have been one or more descrete classes hiding in the prior method, so that I can use "Extract class", where in the new class those out parameters get properties visible to the calling (prior) method.
I consider it bad practice to leave the extracted methods with out parameters in the prior method, skipping the coherent following step of "Extract Class", because if you skip it, those local variables remain in your prior function, but do semantically no longer belong to it.
So, in such a scenario, out parameters in my opinion are a code smell breaking SRP.
在不了解更多背景的情况下,这是一个非常难以回答的问题。
如果 DoSomething 是 UI 层中的一个方法,用于执行与 UI 相关的操作,那么也许没问题。如果 DoSomething 是业务层方法,那么这可能不是一个好方法,因为它意味着业务层需要了解适当的响应可能是什么,甚至可能必须知道是否本地化问题。
纯粹主观地说,我倾向于远离参数。我认为它们破坏了代码的流程并使其变得不太清晰。
This is a really tough question to answer without knowing more about the context.
If
DoSomething
is a method in the UI layer that is do something which is UI related, then perhaps it's okay. IfDoSomething
is a business layer method though, then this is probably not a good approach because it implies that the business layer needs to understand what an appropriate response might be, and it might even have to be aware if localization issues.On a purely subjective note, I've tended to stay away from out parameters. I think they disrupt the flow of the code and make it a little less clear.
我认为最好的方法是使用预期的异常。您可以创建一组定义警告的自定义异常,并在调用方法中捕获它们。
这个想法是在 DoSomething 实现结束时引发异常,以便流程不会在中间停止
I think that the best way to do this is to use expected Exceptions. You can create a set of custom exceptions that define your warnings, and catch them in the calling method.
The idea would be that the exception is raised at the end of the DoSomething implementation, so that the flow doesn't stop in the middle
我认为适合您的情况的最佳解决方案是使用委托而不是 bool。使用如下内容:
您可以传递一个空的 lamda,您不想向用户显示警告。
I think the best best solution for your case is to use a delegate instead of bool. Use something like this:
You can pass an empty lamda where you don't want to display warnings to user.