Search code examples
c#.netshort-circuiting

Can I force my own short-circuiting in a method call?


Suppose I want to check a bunch of objects to make sure none is null:

if (obj != null &&
    obj.Parameters != null &&
    obj.Parameters.UserSettings != null) {

    // do something with obj.Parameters.UserSettings
}

It is an alluring prospect to write a helper function to accept a variable number of arguments and simplify this kind of check:

static bool NoNulls(params object[] objects) {
    for (int i = 0; i < objects.Length; i++)
        if (objects[i] == null) return false;

    return true;
}

Then the above code could become:

if (NoNulls(obj, obj.Parameters, obj.Parameters.UserSettings)) {
    // do something
}

Right? Wrong. If obj is null, then I'll get a NullReferenceException when I try to pass obj.Parameters to NoNulls.

So the above approach is clearly misguided. But the if statement using the && operator works just fine since it is short-circuited. So: is there any way to make a method short-circuited, so that its arguments are not evaluated until explicitly referenced within the method?


Solution

  • Well, this is ugly but...

    static bool NoNulls(params Func<object>[] funcs) {
        for (int i = 0; i < funcs.Length; i++)
            if (funcs[i]() == null) return false;
    
        return true;
    }
    

    Then call it with:

    if (NoNulls(() => obj,
                () => obj.Parameters,
                () => obj.Parameters.UserSettings)) {
        // do something
    }
    

    Basically you're providing delegates to evaluate the values lazily, rather than the values themselves (as evaluating those values is what causes an exception).

    I'm not saying it's nice, but it's there as an option...

    EDIT: This actually (and accidentally) gets to the heart of what Dan was after, I think. All a method's arguments are evaluated before the method itself is executed. Using delegates effectively lets you delay that evaluation until the method needs to call the delegate to retrieve the value.