【问题标题】:Return from parent method inside of Action<string>从 Action<string> 内部的父方法返回
【发布时间】:2013-05-08 20:22:15
【问题描述】:

我正在一个方法内部工作,该方法执行一系列验证检查,如果其中任何一个检查失败,它会调用Action&lt;string&gt; 来运行一些常见的拒绝代码。设置类似于这样:

public void ValidationMethod() {
    Action<string> rejectionRoutine = (rejectionDescription) => {
        // do something with the reject description
        // other common code
    };

    if (condition != requiredValue) {
        rejectionRoutine("Condition check failed");
        // I currently have to put `return` here following every failed check
    }

    // many more checks following this
}

在这个系统中,一旦一个检查验证失败,我就不需要验证其余的,我只想在 Action 中运行常见的拒绝代码并退出该方法。目前要做到这一点,我只需在调用rejectionRoutine 之后的下一行return。我想知道是否有一种方法可以合并从Action 内部返回或终止父方法执行的能力?

我知道这有点挑剔,但我觉得如果其他人需要添加额外的验证检查(他们不必担心将 return 到处都是) 以及将结束执行的常见行为封装在这些情况下应该通用的代码中。

【问题讨论】:

    标签: c# delegates


    【解决方案1】:

    稍微清理一下代码的一种方法是将所有检查外推到一个集合中:

    Dictionary<Func<bool>, string> checks = new Dictionary<Func<bool>, string>()
    {
        {()=> condition != requiredValue, "Condition check failed"},
        {()=> otherCondition != otherRequiredValue, "Other condition check failed"},
        {()=> thirdCondition != thirdRequiredValue, "Third condition check failed"},
    };
    

    如果以特定顺序运行检查很重要(此代码具有不可预测的顺序),那么您可能希望改用 List&lt;Tuple&lt;Func&lt;bool&gt;, string&gt;&gt; 之类的东西。

    var checks = new List<Tuple<Func<bool>, string>>()
    {
        Tuple.Create<Func<bool>, string>(()=> condition != requiredValue
            , "Condition check failed"),
        Tuple.Create<Func<bool>, string>(()=> otherCondition != otherRequiredValue
            , "Other condition check failed"),
        Tuple.Create<Func<bool>, string>(()=> thirdCondition != thirdRequiredValue
            , "Third condition check failed"),
    };
    

    然后您可以使用 LINQ 进行验证:

    var failedCheck = checks.FirstOrDefault(check => check.Item1());
    if (failedCheck != null)
        rejectionRoutine(failedCheck.Item2);
    

    【讨论】:

    • 啊,服务,伟大的思想都一样。在我发现一些没有意义的地方之前,我编写了几乎与此相同的代码。如果在先前的检查应该终止时对其进行评估,则有些检查将引发异常。 IE。 check1 是 value != null,check2 可能会对 value 做一些事情,假设如果我们走到这一步,它就不能为 null
    • @JesseCarter 然后,正如我最后所说,您需要使用List&lt;Tuple&lt;Func&lt;bool&gt;, string&gt;&gt;。只是多了一点代码。
    • 也许我对 Func 中的 bool 的评估方式感到困惑?布尔值的实际评估是否推迟到调用 Func 之前?我认为一旦创建 Func 就会对其进行评估
    • Is the actual evaluation of the bool value deferred until the Func is invoked? 是的。 I assumed that it would be evaluated as soon as the Func was created. 不,不会。
    • 谢谢,我没有意识到它会这样,很高兴知道
    【解决方案2】:

    从 lambda 表达式中的调用方方法返回没有任何意义。
    (如果在方法运行完成后调用呢?)

    相反,您可以将其更改为 Func&lt;string, Whatever&gt; 并返回其值:

    return rejectionRoutine("Condition check failed");
    

    【讨论】:

    • Action 存在于方法的本地内部,所以我看不出如果方法完成运行,如何调用它?如果我从 Func 返回某些东西,我仍然需要在每次检查后执行 if( returnValue == something ) return。还是我错过了这种方法?
    • @JesseCarter:没有什么可以阻止您将委托暴露在方法之外。我不确定你的意思。
    • 我在我的问题中编辑了代码示例,Action 只存在于周围的 Validation 方法的范围内。除了该方法内部,我看不出它如何在任何地方调用。
    • 不幸的是,您的新代码示例@SLaks 解决方案将不起作用,因为该方法没有返回值。
    【解决方案3】:

    作为 SLaks 解决方案的替代方案,如果您的设计允许,您还可以在 rejectionRoutine 中抛出异常。

    【讨论】:

    • 不幸的是,我认为抛出异常不适合当前的设计。谢谢你的想法
    • 异常不应该用于正常的控制流;它们应该用于特殊情况。
    • 我的想法完全是 Servy,如果我尝试这样做,我相信这将是我的代码审查中的共识
    • 是的,这就是为什么我说“如果你的设计允许的话”。我不清楚您的检查条件是否可以证明抛出异常是合理的。
    猜你喜欢
    • 1970-01-01
    • 2016-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-11
    • 1970-01-01
    相关资源
    最近更新 更多