Introduction
This is based on something I found on stack overflow (after a whole day's search). This is something that I needed a lot, especially with DevExpress. So if you have many methods/classes in a tree expression, instead of checking each individual value for Null
before you get the value, I found a way to check if any value is null
and if not, to return the value you are looking for.
Background
This is very helpful in Devexpress as I said but in general in C# also very helpful and also in MVC.
Using the Code
Let's say you have a Class called Contracts
. In this contracts
class, you have all the bookings (Booking
Class) connected to the class. In the Bookings
class, you have the people's details (Person
Class). In that, you have the persons Security clearance with his Username to login to the system (Security
Class). So let's say I want to get the username of the person connected to the contract.
Normally, you will need to get the first value and then the next and next, etc. as follows...
If (Contracts != null && Contracts.Booking != null &&
Contracts.Booking.Person != null && Contracts.Booking.Person.Security != null)
{
string personUsername = Contracts.Booking.Person.Security.Username;
}
Now this can become a drag, especially if you have a multitude of information on which all have different values from different classes. It also takes a lot of effort if something in the code changes or a class changes.
Now what I found to work is to create an extension class in the project that is globally accessible. So I choose common Functions as a place. The method that will be used is a C# built in function called ExpressionVisitor
. I am going to call my class IsNullVisitor
.
The only namespaces required to do this will be the following:
using System;
using System.Linq.Expressions;
using System.Reflection;
For this example, I will only need 2 classes. One that extends ExpressionVisitor
and then a static
class I called helper
. In my helper
class, I have 4 static
objects to do my testing.
So let us start with the ExpressionVisitor
class. Mine looks as follows:
public class IsNullVisitor : ExpressionVisitor
{
public bool IsNull { get; private set; }
public object CurrentObject { get; set; }
protected override Expression VisitMember(MemberExpression node)
{
base.VisitMember(node);
if (CheckNull())
return node;
var member = (PropertyInfo)node.Member;
CurrentObject = member.GetValue(CurrentObject, null);
CheckNull();
return node;
}
private bool CheckNull()
{
if (CurrentObject == null)
IsNull = true;
return IsNull;
}
}
With this, we will use the helpers constructed in Linq expressions to test each 'level' of the classes until a value can be found. But if any one of the objects comes back Null
, it will return null
value.
Now to do this, I will show you the first object I used. This object takes any object and tests whether it has any null
object, if it does not, it will return the object value. I will use a linq expression to check each individual object and if any one is null
, return null
value as follows. Take note that all the objects will be under the Helper
class I created:
public static class Helper
{
}
In this class, I create the isNull
checks required. First being the object that tests and just returns the object as is or the value null
.
public static object IsNullValueReturn<T>
(this T root, Expression<Func<T, object>> getter)
{
var visitor = new IsNullVisitor();
visitor.CurrentObject = root;
visitor.Visit(getter);
If (visitor.IsNull)
return null;
return visitor.CurrentObject;
}
So let us take the above example and see how we will query this...
string personUsername = Contracts.IsNullStringReturn(c => c.Booking.Person.Security.Username);
This will now test until a null
is found. Thus it will test Contracts
and if not null
, it tests Contracts.Booking
and if not null
, keeps testing until it finds a null
. It will continue to iterate through the MemberExpression
until one returns a value true
. Thus it will get the base.Visit
member which will be Contracts
in this case and keep testing until a Null
is found. So it tests the base.VisitMember(MemberExpression)
for null
and returns if true
. If false
, it gets the PropertyInfo
of the MemberExpression
's member and test if the Value
can be got if not it is null
. It then tests for the second time the Null
value and if not null
, it continues on (with the 'tree
') until a null
value causes it to return or null
was not found in which case the final value tested's object can be returned. So in example if nothing tested null
, it returns the Username
value.
The second test I am going to do is one where I specifically wants a string
value to return in the case where the object tested is not a string
value (ToString()
method). Since string
can be Null
, I can still return the value as Null
if null
values were found.
public static string IsNullStringReturn<T>(this T root, Expression<Func<T, object>> getter)
{
var visitor = new IsNullVisitor();
visitor.CurrentObject = root;
visitor.Visit(getter);
if (visitor.IsNull)
return null;
return visitor.CurrentObject.ToString();
}
The third one I will show is to return just the 1st letter or if any null
value, the string 'N/A
'.
public static string IsNullNACharReturn<T>(this T root, Expression<Func<T, object>> getter)
{
var visitor = new IsNullVisitor();
visitor.CurrentObject = root;
visitor.Visit(getter);
if (visitor.IsNull)
return "N/A";
return Format.FirstChar(visitor.CurrentObject.ToString());
}
The code used in my firstChar
method is as below:
public static string FirstChar(string item)
{
if (!String.IsNullOrEmpty(item))
if (item.Trim().Length > 0)
return item.Trim().Substring(0,1);
return string.Empty;
}
This might return a blank value but still you will be able to test if null
or string.Empty
for accurate calculations, etc.
The last one will be testing and returning a bool
value.
public static bool? IsNullBoolReturn<T>(this T root, Expression<Func<T, object>> getter)
{
var visitor = new IsNullVisitor();
visitor.CurrentObject = root;
visitor.Visit(getter);
if (visitor.IsNull)
return null;
return Convert.ToBoolean(visitor.CurrentObject);
}
This method I made a nullable bool
so that you can get a null
value or the bool
value of the object. This way, one can check whether it is null
or not and if not, it will return the Boolean value of the object.
All these are very helpful if you need to return a value without the endless testing. The advantage of how I did it is that you can just use the value straight and if has a nullable object, you will still have a value. So you can use the value without testing for a nullable object first.
There are endless objects you can use and then just customize the return type value, etc. Whether you use like me a different type and as such use different names or just overloaded/override objects with the same name, it is your choice.
Points of Interest
Take note that this is unfortunately not completely idiot proof (and knowing code) on the 1st version ;-). So keep in mind that if you use the following, it will most likely crash and cause errors:
string personUsername = Contracts.IsNullBoolReturn(c => c.Booking.Person.Security.Username);
So when you use this, make sure you use the correct object. Well when in doubt, you can always just use object. :-P
var personUsername = Contracts.IsNullValueReturn(c => c.Booking.Person.Security.Username);
Lastly, be well aware that the downfall of this is that when you use any of the null
checkers to strongly typed values, you must not use the value return. Although the value return is for let's say a string
value, the null visitor will not return a string
according to the code but an unknown variable. So the problem with this is that it does fall short when using the bool and 'N/A' returning values. But I use 90% the isNullValueReturn
, very little the isNullStringReturn
, and only the isNullBoolReturn
and isNullNAReturn
in specific reports.
History