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<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;
}
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<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));
}
but you can create a simplified version of your method and combine it with the IIf
public static bool IsNotNull<TInput>(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);