When working in ASP.NET MVC you sometimes pass a model to your view. In some cases your model is a few levels deep. For example:
Model.User.Address.ZipCode
(Yes this violates LoD but I don't like LoD anyways...)
Well I use models like this all the time and I constantly had to deal with properties being null when I was expecting a value. Since everything in a view gets rendered as string I decided to make a helper method that will allow me to pass anything in and return an empty string if the value was null (null dereferencing) instead of a NullReference Exception. Out came SafeGet. SafeGet is an extension method that applies to any object. It allows you to pass in the property, or value, you want to check as well as any constraints on the value. It's probably easier to see what I mean with code... check out the example:
SafeGet signature:
public static string SafeGet<T>( this T instance, Func<T, object> nonNullFunction, params Func<object>[] nullConstraint ) where T : class
Here is how it works:
In my view I wrap SafeGet around the properties I am not sure will have a value and include any constraints:
<%= Html.TextBox( "BirthDate", Model.User.SafeGet( o => o.BirthDate, () => DateTime.MinValue ) )%>
Yes, it uses Lambda expressions :)
The first param is "nonNullFunction" - this is where you pass in the value you want to check.
The second param is "nullConstraint" - Since I am working with a "DateTime" object (not "Nullable DateTime") I know DateTime must have a value but I also want it to consider the value as null IF the value of "o.DateTime" is "DateTime.MinValue" (basically saying: "if (o.DateTime == DateTime.MinValue) return null;"). You can have many nullConstraints if you need to check multiple values.
SafeGet then returns the value or "string.Empty" if the expression is null or it matches any constraints.
You could probably include another param as a default value to pass if it is null rather than always passing "string.Empty"
If you're using custom ViewModels you could certainly apply this at that level instead of in the view directly. I'm not sure if this breaks Seperation of Concerns by using it in a View.
Here's the SafeGet method:
public static string SafeGet<T>(this T instance, Func<T, object> nonNullFunction, params Func<object>[] nullConstraint) where T : class
{
if(instance != null && nonNullFunction != null)
{
try
{
var o = nonNullFunction(instance);
if(o == null) return string.Empty;
if(nullConstraint != null)
{
// Check each constraint to make sure it doesn't match
foreach(var constraint in nullConstraint)
{
if(constraint().Equals(o)) return string.Empty;
}
}
return o.ToString();
}
catch(NullReferenceException)
{
return string.Empty;
}
}
// in all other cases, return the default
return string.Empty;
}
}