我想知道是否有办法不必重复相同的 if construction ,而是调用 StatusCheck()。成功时它不能返回true。 任何人都知道这个问题有更好的标题吗?
bool Enable()
{
if (!GetStatus(ref status)) { Trace.WriteLine("Error"); return false; }
// do stuff
if (!GetStatus(ref status)) { Trace.WriteLine("Error"); return false; }
// do more stuff
if (!GetStatus(ref status)) { Trace.WriteLine("Error"); return false; }
// do even more stuff
// 6 more times the above
return true;
}
答案 0 :(得分:6)
我会将“Do stuff”表示的代码重构为方法。您调用这些方法并捕获异常或检查这些方法的返回值(可能是当前状态),而不是重复调用GetStatus()
。
另外,我不明白为什么名为GetStatus()
的方法会有一个ref
参数,该参数似乎是由具有当前状态的方法更新的?如果您必须使用GetStatus()
方法GetStatus()
,则不会使用任何参数,而是实际返回当前状态。
即
Status status = GetStatus();
如果您选择允许这些方法抛出异常,那么请注意,当抛出异常时,您不会开始应用实际逻辑 - exceptions are not the right way to control program flow。
答案 1 :(得分:6)
如果状态无效,您可以创建一个抛出异常的CheckStatus()
方法,然后在Enable()
方法中处理该异常:
public void CheckStatus(int status)
{
if (!IsValidStatus(status)) {
throw new InvalidStatusException(status);
}
}
public bool Enable()
{
try {
CheckStatus(status);
// do stuff
CheckStatus(status);
// do more stuff
CheckStatus(status);
// do even more stuff
// 6 more times the above
return true;
} catch (InvalidStatusException) {
Trace.WriteLine("Error");
return false;
}
}
答案 2 :(得分:5)
根据你想要的严肃程度,你可以建立某种行动队列来打破方法中的“做事”。
protected delegate void DoStuffDelegate(ref {TYPE} statusToCheck);
bool Enable()
{
List<DoStuffDelegate> stuffToDo = new ...
stuffToDo.Add(myFirstMethod);
stuffToDo.Add(mySecondMethod);
foreach(var myDelegate in stuffToDo)
{
if(!GetStatus(ref status)) { Trace.WriteLine("Error"); return false; }
myDelegate(ref status);
}
}
对于好的和坏的C#都不允许任何其他构造(如预处理器定义或我们在C ++中得到的)。
答案 3 :(得分:1)
您可以使用例外,并让异常向上传播。
void GetStatusAndException(ref Status) {
if (!GetStatus(ref status))) Throw new Exception("Status exception");
}
如果您不想要例外,那就是 除了将返回之外的所有内容放入方法之外,你无能为力:
bool GetStatusAndTrace(ref Status) {
bool result = GetStatus(ref status))
if (!result) Trace.WriteLine("Error");
return result;
}
bool Enable()
{
if (!GetStatusAndTrace(ref status)) return false;
// do stuff
if (!GetStatusAndTrace(ref status)) return false;
// do more stuff
if (!GetStatusAndTrace(ref status)) return false;
// do even more stuff
// 6 more times the above
return true;
}
答案 4 :(得分:1)
一种可能的解决方案是为您正在使用的API创建一个“健全”包装器:
class Wrapper
{
public void DoStuff() // Add static modifiers, parameters and return values as necessary
{
API.DoStuff();
CheckStatus();
}
public void DoSomeOtherStuff()
{
API.DoSomeOtherStuff();
CheckStatus();
}
private void CheckStatus()
{
Status status = default(Status);
if(!GetStatus(ref status)) throw new InvalidStatusException();
}
}
一些工作,但它允许您的客户端代码更具可读性:
bool Enable()
{
try
{
Wrapper.DoStuff();
Wrapper.DoSomeMoreStuff();
return true;
}
catch(InvalidStatusException)
{
Trace.WriteLine("Error");
return false;
}
}
答案 5 :(得分:1)
现在您不需要使用异常,它仍然可以阅读。无论如何,你仍然需要打电话。例外花费大约4000-8000个时钟周期。
bool Enable()
{
if (GetStatus(ref status))
{
// do stuff
if (GetStatus(ref status))
{
// do stuff
if (GetStatus(ref status))
{
// do stuff
return true;
}
}
}
Trace.WriteLine("Error");
return false;
}
答案 6 :(得分:1)
使用LINQ,您可以执行以下操作:
delegate bool StatusFunc( ref int status );
bool Enable()
{
var funcs = new StatusFunc[]
{
GetStatusA,
GetStatusB,
GetStatusC
};
return funcs.All( f => f( ref status ) );
}
请注意,它有点像黑客,因为GetStatus
函数有副作用(修改状态),这在LINQ查询中是禁止的。
答案 7 :(得分:1)
这个怎么样?它只需要对现有代码进行最少的更改。 yield return
是你的朋友;让编译器完成所有脏工作:
IEnumerable<bool> StatusChecks()
{
// Do stuff
yield return GetStatus( ref status );
// Do stuff
yield return GetStatus( ref status );
// Do stuff
yield return GetStatus( ref status );
}
bool Enable()
{
foreach ( var b in StatusChecks() )
{
if ( !b )
{
Trace.WriteLine("Error");
return false;
}
}
return true;
}
或者,如果您不介意带副作用的LINQ查询,只需:
bool Enable()
{
var result = StatusChecks().All( b => b );
if ( !result )
{
Trace.WriteLine("Error");
}
return result;
}
答案 8 :(得分:0)
bool Enable()
{
try {
if (!newProc }
// do stuff
if (!newProc }
// do more stuff
if (!newProc }
// do even more stuff
// 6 more times the above
return true;
}
catch {
return false;
}
}
public function newProc()
{
if (!GetStatus(ref status)) { Trace.WriteLine("Error"); return false; }
throw new Exception
}
答案 9 :(得分:0)
将代码包装在try-catch块中,并重写GetStatus()以在出错时抛出异常。如果您想通过本书来实现,请实现从System.Exception继承的自己的异常。然后,如果稍后需要该信息,也可以将“status”属性添加到异常中(但是您的代码示例并未表明这一点)。
这样的事情:
bool Enable()
{
try
{
GetStatus(ref status);
// do stuff
GetStatus(ref status);
// do more stuff
GetStatus(ref status);
// do even more stuff
// 6 more times the above
return true;
}
catch (Exception ex)
{
Trace.WriteLine("Error");
return false;
}
}
就像我说的那样,抛出和捕获的异常应该是一个自定义异常,但上面的方法会有效。
答案 10 :(得分:0)
让我们看看我是否理解你。
您可以使用规范设计模式: http://en.wikipedia.org/wiki/Specification_pattern
您应该使用类似于上述设计模式的实现,而不是使用带编码的验证,因为它为您提供了一种更加可扩展的方法来针对对象状态添加规则。
例如,您要定义一个规范“StatusSpecification”,它“用于验证状态是否正确”。结果可能是布尔值。
破坏的规则评估程序会获取该布尔结果并执行所需的决策(抛出异常?尝试恢复?结束应用程序?只是注意用户有关错误的信息?报告错误?)。
总结:您需要有一些“规范加载器”并针对对象类型的加载规则执行对象状态。最后,在这种情况下,您将在一行中评估该状态(从消费者的角度来看),也许,布尔结果可能是您的属性标志。