c#如何';如果不为空则返回';在一艘客轮上?

c#如何';如果不为空则返回';在一艘客轮上?,c#,C#,如果不为null或继续执行,是否有一个单行程序返回某个内容,或者如何使该内容成为空? 所有这些都是为了避免在几种方法中复制IF行 初始代码如下: var error = ValidateStuff(someArg); if (error != null) { return error; } DoOtherStuff(); 那么,如何重构它以避免在任何地方都复制粘贴相同的内容呢? 伪代码类似于 ValidateStuff(someArg) ? return ___ : continue;

如果不为null或继续执行,是否有一个单行程序返回某个内容,或者如何使该内容成为空? 所有这些都是为了避免在几种方法中复制IF行

初始代码如下:

var error = ValidateStuff(someArg);
if (error != null)
{
    return error;
}
DoOtherStuff();
那么,如何重构它以避免在任何地方都复制粘贴相同的内容呢? 伪代码类似于

ValidateStuff(someArg) ? return ___ : continue;
DoSomethingElse();
AndMoreStuff();
-编辑- 一个更简单的例子,为了澄清一些答案和评论中的疑问:

public string Foo(string arg)
{
    string fuu = GetMeSomething(arg);

    if(fuu != null) return fuu;

    ImDoingThings();

    return "I did things";
}
如果有这个,那就太棒了:

public string Foo(string arg)
{
    ReturnIfNotNull(GetMeSomething(arg));

    ImDoingThings();

    return "I did things.";
}
当然可以:

在您的代码中:

ValidateStuff(someArg);
DoOtherStuff();
注意:我经常将
ValidateStuff
中的通用代码与
中的if(DEBUG)[…]else[…]else[…]endif
组合在一起,这样与生产无关的内容就不会最终出现在生产二进制文件中


警告呢

为此,我使用了一些技巧:

  • 仅当确实需要时才构建错误对象
  • 类似地,仅当某些操作失败时才构建错误列表
  • 利用“使用”来简化编码。我是一个懒惰的程序员。。。但这是一个小风险;如果你忘了使用,你就有麻烦了。。。尽管如此,我认为这种风险比“让我们继续表演,忘记最初的警告”要好
  • 如果您有一个更好的警告处理程序(so:而不是异常),请使用它并处理它
  • 如果发生错误,则丢弃该批次
  • 很明显,你可以根据自己的需要扩展它

    无需进一步到期:

    public class WarningsHandler : IDisposable
    {
        private List<WarningErrorBase> errors = null;
    
        // Default handler. Remember to use 'using', or otherwise you'll end up 
        // with pain and suffering!
        public void Dispose()
        {
            var errors = FetchValidationResults();
    
            if (errors != null && errors.Count > 0)
            {
                throw new ValidationException(errors);
            }
        }
    
        // Handler if you have a better idea than using an Exception
        public IEnumerable<Error> FetchValidationResults() 
        {
            var errors = this.errors;
            this.errors = null;
            return errors;
        }
    
        public void Warn(bool condition, Func<Warning> errorBuilder)
        {
            if (condition) 
            { 
                if (errors == null) { errors = new List<WarningErrorBase>(); }
                errors.Add(errorBuilder()); 
            }
        }
    
        public void Error(bool condition, Func<Error> errorBuilder)
        {
            if (condition) 
            { 
                if (errors == null) { errors = new List<WarningErrorBase>(); }
                errors.Add(errorBuilder()); 
    
                throw new ValidationException(FetchValidationResults());
            }
        }
    }
    

    好的,再来一个小把戏。:-)

    将不同错误消息与少量开销混合的最后一种方法是使用
    屈服返回
    。这使您能够返回具有不同行为的多个结果值。空值可以被忽略

    首先,我们需要一大堆包装纸:

    // We need some base interface that we can use for return values
    public interface IResult { }
    
    // We have to wrap normal return values
    public class Result<T> : IResult
    {
        public Result(T result) { this.Value = result; }
    
        public T Value { get; private set; }
    }
    
    // A few classes for messages, errors, warnings, ...
    public class Message : IResult
    {
        public Message(string format, params object[] args)
        {
            this.Text = string.Format(format, args);
        }
    
        public string Text { get; private set; }
    
        internal virtual void Handle(List<Message> messages)
        {
            messages.Add(this);
        }
    }
    
    public class Error : Message
    {
        public Error(Exception ex) :
            base("Uncaught exception: {0}", ex.Message)
        { }
    
        public Error(string format, params object[] args) : 
            base(format, args)
        { }
    
        internal override void Handle(List<Message> messages)
        {
            throw new ValidationException(this.Text);
        }
    }
    
    // Other wrappers like warnings, etc. 
    // Wrapping IEnumerable<IResult> is useful too.
    

    我认为最好的验证方法是抛出一个自定义异常。 (CustomException是从Exception类继承的我自己的类)

    比如说,, 我在我的业务层中使用它:(在数据库中保存模型或其他东西)

    在表示层:

    try
    {
       var model = new someModel{ fill properties of model };
    
       var service = new SomeService();
       service.DoSomething(model);
    
       DoOtherStuff();
    }
    catch(CustomException ex)
    {
      ShowMessageToUser(ex.Message);
    }
    
    注意:我只捕获自定义异常,而不是业务异常

    这是我亲爱的验证参数和模型的战争


    我希望这能有所帮助。

    首先,你可能用了错误的方法;您可能会更好地抛出异常,而不是试图返回错误代码

    但是。。。您可以使用lambdas使类似于伪代码的东西工作。它会变得混乱(对于泛型会更混乱),但为了完整性和回答您的具体问题:

    static Error ReturnIf(Error error,
        Func<Error, bool> predicate,
        Func<Error> rest)
    {
        return predicate(error) ? error : rest();
    }
    
    static Error Test2(bool someArg)
    {
        return ReturnIf(ValidateStuff(someArg), error => error != null, () =>
        {
            DoSomethingElse();
            AndMoreStuff();
            return null;
        });
    }
    
    静态错误返回IF(错误,
    Func谓词,
    Func(休息)
    {
    返回谓词(错误)?错误:rest();
    }
    静态错误Test2(bool someArg)
    {
    返回ReturnIf(ValidateStuff(someArg),error=>error!=null,()=>
    {
    DoSomethingElse();
    AndMoreStuff();
    返回null;
    });
    }
    
    或者,由于您实际上已经说过“如果不为null,则返回”,因此代码应该简化并更加具体:

    static Error ReturnIfNotNull(Error error,
           Func<Error> rest)
    {
        return error ?? rest();
    }
    
    static Error Test2(bool someArg)
    {
        return ReturnIfNotNull(ValidateStuff(someArg) () =>
        {
            DoSomethingElse();
            AndMoreStuff();
            return null;
        });
    }
    
    静态错误ReturnIfNotNull(错误,
    Func(休息)
    {
    返回错误??rest();
    }
    静态错误Test2(bool someArg)
    {
    return ReturnIfNotNull(ValidateStuff(someArg)(=>
    {
    DoSomethingElse();
    AndMoreStuff();
    返回null;
    });
    }
    

    我并不是说你真的想在你的特殊情况下使用这样的代码。。。尽管对这项技术进行了广泛的探索。

    这个函数的范围是什么?你们有不同的类,它们都有一个验证然后再执行的功能吗?它们背后有共同的目的吗?你不能,你所能做的就是将代码最小化,省去return语句周围的大括号。如果你主要期望有效输入,你可以使用
    EnsureStuffValid(someArg)
    不返回任何内容,如果内容无效,则抛出异常。我绝对建议切换到C#-异常中提供的标准错误返回机制。它们不必手动传播到调用堆栈中,这就是您在这里所做的。您可以使
    ValidateStuff
    返回一个
    布尔值(
    false
    ,如果验证失败)。然后可以通过
    out
    ref
    参数返回验证错误,而不是作为函数的返回值<代码>字符串错误;如果(!ValidateStuff(out errors)){return errors;}
    Wait,我认为在C#中可以避免的情况下引发异常是个好主意。实际上,我会说老年退休金计划的版本更好,但这就是为什么我要问你对此有何看法。特别是当它是可以恢复的时候。在本例中,只有当代码能够以有意义的方式从错误中恢复时,他的错误列表才会很大。否则,返回一个错误对象而不是抛出一个异常永远都不是一个好主意。@thinklarge exception用于需要异常的东西。在C#中抛出异常的速度相对较慢,这就是为什么引入了
    int.TryParse
    之类的东西。尽管如此,我还是不会回避他们。因此,在验证列表的情况下,我会推迟
    抛出
    ,直到我完成所有验证(将其添加到列表中,然后立即抛出整个列表)。@atlaste Ok,因此我的理解是正确的。这是你的回答对OPs post的假设(假设这是一个验证,所以不是一个坏的假设),但是如果他能够恢复到这一点以上,那么他不会返回一个错误,因为他确实是一个更好的解决方案吗?我们在代码中做了一些类似的事情,出现了严重错误,但也发出了警告。我们还希望在返回时向用户提供所有错误,以便用户可以同时解决所有错误。所以我们很少抛出异常,除非我们的代码看到了异常并说“不,不,我不能处理它”。@thinklarge啊,警告。干得好。[添加到
    public IEnumerable<IResult> MyMethod()
    {
        // Delegate validation to somewhere else. You might wrap an IEnumerable<IResult> here:
        yield return ValidateStuff(someArg);
    
        // Information messages, etc
        yield return new Message("Hello world!");
    
        // You might end up with an Exception you didn't expect...
        var tmp = new List<int>();
        tmp[2] = 2; // oopz...
    
        // ...
        yield return new Result<int>(12); // return 12;
    }
    
    int result = MyMethod().Execute<int>();
    
    public class SomeService
    {
    
        public void DoSomething(some params or some instance of a model class)
        {
            Validate(some params or an instance of a model class);
    
            // some other codes such as save data in database or etc ...
    
        }
    
        private void Validate(some params or an instance of a model class)
        {
            if(something is wrong)
                throw new CustomException("X is invalid"); // X is the name of wrong param
        }
    
    }
    
    try
    {
       var model = new someModel{ fill properties of model };
    
       var service = new SomeService();
       service.DoSomething(model);
    
       DoOtherStuff();
    }
    catch(CustomException ex)
    {
      ShowMessageToUser(ex.Message);
    }
    
    static Error ReturnIf(Error error,
        Func<Error, bool> predicate,
        Func<Error> rest)
    {
        return predicate(error) ? error : rest();
    }
    
    static Error Test2(bool someArg)
    {
        return ReturnIf(ValidateStuff(someArg), error => error != null, () =>
        {
            DoSomethingElse();
            AndMoreStuff();
            return null;
        });
    }
    
    static Error ReturnIfNotNull(Error error,
           Func<Error> rest)
    {
        return error ?? rest();
    }
    
    static Error Test2(bool someArg)
    {
        return ReturnIfNotNull(ValidateStuff(someArg) () =>
        {
            DoSomethingElse();
            AndMoreStuff();
            return null;
        });
    }