我刚刚为我编写的方法添加了 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 参数是不好的做法,如果是,我该怎么做呢?
答案 0 :(得分:9)
在void方法中使用out参数通常是个坏主意。你说你已经使用它“而不是让方法本身返回false / true,因为这意味着DoSomething失败/成功” - 我不相信这意味着什么。通常在.NET中,故障通过异常而不是真/假来表示。
out
参数通常比返回值更难使用 - 特别是,你必须有一个正确类型的变量来处理,所以你不能只写:
if (DoSomething(...))
{
// Warn user here
}
您可能需要考虑的一个替代方案是指示所需警告级别的枚举。例如:
public enum WarningLevel
{
NoWarningRequired,
WarnUser
}
然后该方法可以返回WarningLevel
而不是bool
。这会让你更清楚你的意思 - 尽管你可能想稍微重命名一下。 (很难用“DoSomething”这样的metasyntactic名称给出建议,虽然我完全理解你为什么在这里使用它。)
当然,另一种选择是您可能希望存在更多信息 - 例如警告的原因。这可以通过枚举完成,或者您可能想要完全提供更丰富的结果。
答案 1 :(得分:7)
out
非常一个有用的构造,特别是在bool TryGetFoo(..., out value)
这样的模式中,你想要知道“if”和单独的“什么”(和可空的不一定是一种选择)。
然而 - 在这种情况下,为什么不这样做:
public bool DoSomething(int id, string input);
并使用返回值发出信号?
答案 2 :(得分:3)
还有一些想法:
FxCop说:CA1021: Avoid out parameters
对于私有/内部方法(实施细节)out
/ ref
参数不是问题
C# 7 Tuples通常是out
参数的更好替代
此外,C# 7通过引入“输出变量”并允许“丢弃”out
参数来改进呼叫网站上out
参数的处理
答案 3 :(得分:1)
在不了解更多相关背景的情况下,这是一个非常棘手的问题。
如果DoSomething
是UI层中的某个与UI相关的方法,那么也许没关系。如果DoSomething
是业务层方法,那么这可能不是一个好方法,因为它意味着业务层需要了解适当的响应可能是什么,甚至可能必须知道本地化问题。
纯粹主观地说,我倾向于远离参数。我认为它们破坏了代码的流程并使其不那么清晰。
答案 4 :(得分:1)
鉴于一个很大的遗留代码方法(比如15行以上,200多行的遗留代码方法很常见),人们可能想要使用&#34;提取方法&#34;重构以清理并使代码更简洁,更易于维护。
这样的重构很可能产生一个或多个新方法,其中包含用于设置先前方法局部变量值的参数。
就个人而言,我使用这种情况作为一个强有力的指标,表明在先前的方法中隐藏了一个或多个离散类,因此我可以使用&#34;提取类&#34;,在新类中的那些参数获取调用(先前)方法可见的属性。
我认为在先前的方法中保留带有out参数的提取方法是不好的做法,跳过&#34; Extract Class&#34;的连贯的后续步骤,因为如果你跳过它,那些局部变量保留在你的先验功能,但在语义上不再属于它。
所以,在这种情况下,我认为out参数是破坏SRP的代码味道。
答案 5 :(得分:0)
我认为最好的方法是使用预期的例外。您可以创建一组定义警告的自定义异常,并在调用方法中捕获它们。
public class MyWarningException : Exception() {}
...
try
{
obj.DoSomething(id,input);
}
catch (MyWarningException ex)
{
// do stuff
}
想法是在DoSomething实现结束时引发异常,以便流程不会在中间停止
答案 6 :(得分:0)
我认为针对您的案例的最佳解决方案是使用委托代替bool。使用这样的东西:
public void DoSomething(int id, string input, Action warnUser);
您可以传递空的lamda,而不想向用户显示警告。