C#要么返回false,要么什么都不做

时间:2011-01-25 12:21:30

标签: c# .net if-statement return

我想知道是否有办法不必重复相同的 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;
}

11 个答案:

答案 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”,它“用于验证状态是否正确”。结果可能是布尔值。

破坏的规则评估程序会获取该布尔结果并执行所需的决策(抛出异常?尝试恢复?结束应用程序?只是注意用户有关错误的信息?报告错误?)。

总结:您需要有一些“规范加载器”并针对对象类型的加载规则执行对象状态。最后,在这种情况下,您将在一行中评估该状态(从消费者的角度来看),也许,布尔结果可能是您的属性标志。