I have a class represent a generic filter object
public class Filter
{
public string column { get; set; }
public string operator { get; set; }
public string data { get; set; }
}
that I am able to transform in a LambdaExpression thanks to code like this
public LambdaExpression ToExpression( IQueryable query ) {
LambdaExpression toReturn = null;
ParameterExpression parameter = Expression.Parameter( query.ElementType, "p" );
MemberExpression memberAccess = GetMemberExpression( column, parameter );
ConstantExpression filter = Expression.Constant( Convert.ChangeType( data, memberAccess.Type ) );
WhereOperation condition = (WhereOperation)StringEnum.Parse( typeof( WhereOperation ), operator );
LambdaExpression lambda = BuildLambdaExpression( memberAccess, filter, parameter, condition, data );
if ( toReturn == null ) {
toReturn = lambda;
}
return toReturn;
}
As per the requirement the Filter member column can contains a sort of navigation sintax for querying fields that is expressed like FieldA.FieldB.Description that translates to:
- Get the value of type T returned from the FieldA property
- Get the value of type T1 returned from the FieldB of T
- Get the value of type T2 returned from the Description of T2
The result is a lambda like this one: p.FieldA.FieldB.Description == "data"
and I can use this result as a parameter of the Where extension method of any IQueryable
The problem comes out when one of the members of the navigation query is a Nullable type. In that case, supposing FieldA is nullable, the correct lambda should be
p.FieldA != null && p.FieldA.FieldB.Description == "data"
I have tried to implement this check while constructing the MemberExpression object using code like this one
MemberExpression memberAccess = null;
foreach ( var property in column.Split( '.' ) ) {
memberAccess = MemberExpression.Property( memberAccess ?? ( p as Expression ), property );
Type memberType = memberAccess.Type;
if ( memberType.IsGenericType &&
memberType.GetGenericTypeDefinition() == typeof( Nullable<> ) ) {
//Create here an expression of type : memberAccess != null
}
}
that is good for primitive types but does not work, for example, with other object references, like EF EntityReference object instances.
I know I could simply add another condition to the previous if like
if ( ( memberType.IsGenericType &&
memberType.GetGenericTypeDefinition() == typeof( Nullable<> ) ) ||
memberType.IsClass ) {
}
but that seems to me too much generic producing a lambda with too many condition and most of them maybe unuseful.
Is there any way to better individuate nullable references?
You can make the null check unconditional. Checking a value type for null is not illegal.