HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Calling a function on an object if not null

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
nullfunctionobjectcallingnot

Problem

Here is code for check null in object:

public static TResult IfNotNull(this TInput obj, Func expression)
    {
        if (obj == null || expression == null) return default(TResult);
        var value = expression(obj);
        return value;
    }


The above code is best pratice of check nullability in object. I'm working on c# V4.0.

Example usage :

Person.IfNotNull(x => x.User).IfNotNull(x => x.Name) ?? "";

Solution

To be sure it always works you should add a constraint to the method:

where TInput : class


This will ensure that TInput is a reference type.

It makes no sense to call it on structs. For them, you need another overload with a different constraint and some ? question marks:

public static TResult IfNotNull(
     this TInput? obj, 
     Func expression
) where TInput : struct
{
    if (!obj.HasValue) return default(TResult);
    var value = expression(obj.Value);
    return value;
}


Someone may ask at this point: but why do we need two extensions if theoretically a single one does the job too?

Consider this:

((decimal?)2).IsNotNull(x => x.Value * 2)


With a single extension you need to use the .Value property for nullable types. With two extensions you get a clean value so you just do

((decimal?)2).IsNotNull(x => x * 2)


But isn't this just a convenience? Of course it is. Don't we write extensions exactly for that reason?

As a matter of fact I use a similar code myself:

public static TResult IIf
(
    this TArg arg,
    Func predicate,
    Func ifTrue,
    Func ifFalse = null
)
{
    if (predicate == null) { throw new ArgumentNullException(nameof(predicate)); }
    if (ifTrue == null) { throw new ArgumentNullException(nameof(ifTrue)); }

    return predicate(arg) ? ifTrue(arg) : (ifFalse == null ? default(TResult) : ifFalse(arg));
}


but you can create a simplified version of your method and combine it with the IIf

public static bool IsNotNull(this TInput obj) where TInput : class
{
    return obj != null;
}


to do this

Person
    .IIf(p => p.IsNotNull(), p => p.User)
    .IIf(u => u.IsNotNull(), u => u.Name, u string.Empty);

Code Snippets

where TInput : class
public static TResult IfNotNull<TInput, TResult>(
     this TInput? obj, 
     Func<TInput, TResult> expression
) where TInput : struct
{
    if (!obj.HasValue) return default(TResult);
    var value = expression(obj.Value);
    return value;
}
((decimal?)2).IsNotNull(x => x.Value * 2)
((decimal?)2).IsNotNull(x => x * 2)
public static TResult IIf<TArg, TResult>
(
    this TArg arg,
    Func<TArg, bool> predicate,
    Func<TArg, TResult> ifTrue,
    Func<TArg, TResult> ifFalse = null
)
{
    if (predicate == null) { throw new ArgumentNullException(nameof(predicate)); }
    if (ifTrue == null) { throw new ArgumentNullException(nameof(ifTrue)); }

    return predicate(arg) ? ifTrue(arg) : (ifFalse == null ? default(TResult) : ifFalse(arg));
}

Context

StackExchange Code Review Q#146483, answer score: 6

Revisions (0)

No revisions yet.