C # how to "return if not null" in one liner?

Is there a single liner to return something if it is nonzero or keep executing, or how to do it? All of this to avoid copying IF pasta lines in multiple ways.

Source:

var error = ValidateStuff(someArg);
if (error != null)
{
    return error;
}
DoOtherStuff();

      

So how do you refactor it to avoid copying pasting the same if all over the place? The pseudocode would be something like

ValidateStuff(someArg) ? return ___ : continue;
DoSomethingElse();
AndMoreStuff();

      

-EDIT- An even more simplified example to clear up some doubts in some of the answers and comments:

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

    if(fuu != null) return fuu;

    ImDoingThings();

    return "I did things";
}

      

It would be great to have this:

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

    ImDoingThings();

    return "I did things.";
}

      

+3


source to share


3 answers


Sure:

void ValidateStuff(someArg) { 
    if (!validation(someArg)) { 
        throw new ValidationException("Whatever went wrong...", errorDetails);
    }
}

      

And in your code:

ValidateStuff(someArg);
DoOtherStuff();

      

PS: I often combine common code in ValidateStuff

c #if (DEBUG) [...] #else [...] #endif

so that production of irrelevant things does not end up in derived binaries.


How about warnings?

I use several tricks for this:

  • Only create an error object if you really need it.
  • Likewise, create an error list only in case of failure.
  • Use "use" for easy coding. I'm a lazy coder ... It's a small risk though; if you forget to use it, you're in trouble ... However, I think this risk is better than the alternative to "let go of the show and forget that there was something warning in the first place."
  • If you have a better handler for your warnings (so: instead of an exception), use that and do with it.
  • If an error occurs, drop the lot.

Obviously, you can renew it as you see fit.

Without further use:

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());
        }
    }
}

      

How to use it?



void MyThing()
{
    using (var handler = new WarningsHandler())
    {
        handler.Error(foo == null, "Foo must have a value");
        handler.Warn(foo.Count > 2, () => new Warning("You should have less than 2 foo present.");
        // etc.
    }
} 

      


Ok, one more trick. :-)

The last way to combine different error messages with little overhead is to use yield return

. This allows you to return multiple result values ​​with different behavior. Zero values ​​can be trivially ignored.

First we need a whole bunch of wrappers:

// 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.

      

Next, we'll need a helper method to execute our methods, which now return IEnumerable instead of a regular type. To do this, I add a helper class that mainly handles execution, expansion, and return values.

public static class ExecutionEngine
{
    public static T Execute<T>(this IEnumerable<IResult> method)
    {
        List<Message> messages = new List<Message>();
        try
        {
            foreach (var item in method)
            {
                // yield return null is ignored here:
                if (item != null)
                {
                    // Handle validation results, messages, etc
                    Message msg = item as Message;
                    if (msg != null)
                    {
                        msg.Handle(messages);
                    }

                    Result<T> returnValue = item as Result<T>;
                    if (returnValue != null)
                    {
                        return returnValue.Value;
                    }

                    // handle other things, error if something wrong
                }
            }

            throw new Exception("Method finished without a return value.");
        }
        catch (ValidationException)
        {
            // TODO: handle messages?

            throw;
        }
        catch (Exception ex)
        {
            // TODO: handle messages?

            var error = new Error(ex);
            error.Handle(messages);

            throw; // unreachable because Error throws. This is to make sure it all compiles
        }
    }
}

      

Once we are all right, the code itself will be pretty simple and it will look like you as usual. The main difference is that you just add "yield return" everywhere, sometimes with an extra wrapper:

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;
}

      

All that remains is what you can no longer name MyMethod

. This can be easily set using the runtime engine:

int result = MyMethod().Execute<int>();

      

+11


source


First, you are more likely to do it wrong; you will probably heavily avoid throw

ing exceptions rather than trying to return error codes.

But ... you can do something like your own pseudocode work using lambdas. It gets messy (and will be even more messy with generics), but for completeness and to answer your specific question:

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;
    });
}

      



Or, since you actually said "return if not null", code a will be simplified and more specific:

static Error ReturnIfNotNull(Error error,
       Func<Error> rest)
{
    return error ?? rest();
}

static Error Test2(bool someArg)
{
    return ReturnIfNotNull(ValidateStuff(someArg) () =>
    {
        DoSomethingElse();
        AndMoreStuff();
        return null;
    });
}

      

I am not suggesting that you really want to use code like this in your particular situation ... Although Bart de Smet has researched this method extensively.

+1


source


I think the best way to check is to throw a custom exception. (CustomException is my own class inherited from Exception class)

for example, I am using this in my business layer: (save model to database or whatever)

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
    }

}

      

and in the presentation layer:

try
{
   var model = new someModel{ fill properties of model };

   var service = new SomeService();
   service.DoSomething(model);

   DoOtherStuff();
}
catch(CustomException ex)
{
  ShowMessageToUser(ex.Message);
}

      

Note. I will only catch my custom exceptions, not business exceptions.

This is my dear war for parameter and model validation

Hope this helps.

-1


source







All Articles