adam0101 adam0101 - 4 months ago 16
C# Question

Function to return a function that returns a function, etc

Is it possible to define a function in a way that it basically returns itself as a delegate?

For example, if this was valid syntax:

public class Scrub
{
public NotNull NotNull<T>(T value, string name)
{
if (value == null) throw new ArgumentNullException(name);
return NotNull;
}
}


Then I could chain method calls together like this.

Scrub.NotNull(param1, nameof(param1))(param2, nameof(param2)(param3, nameof(param3));

Answer

Well yes, you can, with your own delegate declaration:

delegate SelfReturner<T> SelfReturner<T>(T value, string name);

static SelfReturner<T> NotNull<T>(T value, string name)
{
    if (value == null) throw new ArgumentNullException(name);
    return NotNull;
}

... but it doesn't seem useful to me. Any reason you really want to do this, rather than just making three separate calls? For example, I have a Preconditions.CheckNotNull which returns the non-null value - I find that a lot more useful than this looks, to be honest.

As noted in comments, the above only works if all the parameters are of the same type (or all implicitly convertible to the type of the first parameter). An alternative to allow chaining with a bit more work would be to use a singleton instance with a generic method:

public sealed class NullChecker
{
    public static NullChecker Instance { get; } = new NullChecker();
    private NullChecker() {}

    public static NullChecker Scrub<T>(T value, string paramName) where T : class
    {
        if (value == null)
        {
            throw new ArgumentNullException(paramName);
        }
        return this;
    }
}

Use as:

NullChecker.Instance.Scrub(param1, nameof(param1))
                    .Scrub(param2, nameof(param2))
                    .Scrub(param3, nameof(param3));

With two separate methods, one static and one not (but with different names) you could remove the Instance part. For example:

NullChecker.Scrub(param1, nameof(param1))
           .And(param2, nameof(param2))
           .And(param3, nameof(param3));