How do i know when a lambda expression is null - c#

I need to programatically check whether a nested property/function result in a lambda expression is null or not. The problem is that the null could be in any of the nested subproperties.
Example. Function is:
public static bool HasNull<T, Y>(this T someType, Expression<Func<T, Y>> input)
{
//Determine if expression has a null property
}
Use:
person.HasNull(d=>d.addressdetails.Street)
person.HasNull(d=>d.addressdetails[1].Street)
person.HasNull(d=>d.addressdetails.FirstOrDefault().Street)
person.HasNull(d=>d.InvoiceList.FirstOrDefault().Product.Name)
In any of the examples addressdetails or street, or invoicelist or the product or the name could be null.The code will throw an exception if i try to invoke the function and some nested property is null.
Important: I don't want to use a try catch for this because that is desastrous for the debugging performance.
The reason for this approach is to quickly check for values while i don't want to forget any nulls and so cause exceptions. This is handy for reporting solutions and grids where a null on the report can just show empty and has no futher business rules.
related post: Don't stop debugger at THAT exception when it's thrown and caught

It is possible, but I'm not sure I would recommand it. Here is something that you may find usefull: it doesn't return a boolean, but instead, the leaf value of the expression if possible (no null reference).
public static class Dereferencer
{
private static readonly MethodInfo safeDereferenceMethodInfo
= typeof (Dereferencer).GetMethod("SafeDereferenceHelper", BindingFlags.NonPublic| BindingFlags.Static);
private static TMember SafeDereferenceHelper<TTarget, TMember>(TTarget target,
Func<TTarget, TMember> walker)
{
return target == null ? default(TMember) : walker(target);
}
public static TMember SafeDereference<TTarget, TMember>(this TTarget target, Expression<Func<TTarget, TMember>> expression)
{
var lambdaExpression = expression as LambdaExpression;
if (lambdaExpression == null)
return default(TMember);
var methodCalls = new Queue<MethodCallExpression>();
VisitExpression(expression.Body, methodCalls);
var callChain = methodCalls.Count == 0 ? expression.Body : CombineMethodCalls(methodCalls);
var exp = Expression.Lambda(typeof (Func<TTarget, TMember>), callChain, lambdaExpression.Parameters);
var safeEvaluator = (Func<TTarget, TMember>) exp.Compile();
return safeEvaluator(target);
}
private static Expression CombineMethodCalls(Queue<MethodCallExpression> methodCallExpressions)
{
var callChain = methodCallExpressions.Dequeue();
if (methodCallExpressions.Count == 0)
return callChain;
return Expression.Call(callChain.Method,
CombineMethodCalls(methodCallExpressions),
callChain.Arguments[1]);
}
private static MethodCallExpression GenerateSafeDereferenceCall(Type targetType,
Type memberType,
Expression target,
Func<ParameterExpression, Expression> bodyBuilder)
{
var methodInfo = safeDereferenceMethodInfo.MakeGenericMethod(targetType, memberType);
var lambdaType = typeof (Func<,>).MakeGenericType(targetType, memberType);
var lambdaParameterName = targetType.Name.ToLower();
var lambdaParameter = Expression.Parameter(targetType, lambdaParameterName);
var lambda = Expression.Lambda(lambdaType, bodyBuilder(lambdaParameter), lambdaParameter);
return Expression.Call(methodInfo, target, lambda);
}
private static void VisitExpression(Expression expression,
Queue<MethodCallExpression> methodCallsQueue)
{
switch (expression.NodeType)
{
case ExpressionType.MemberAccess:
VisitMemberExpression((MemberExpression) expression, methodCallsQueue);
break;
case ExpressionType.Call:
VisitMethodCallExpression((MethodCallExpression) expression, methodCallsQueue);
break;
}
}
private static void VisitMemberExpression(MemberExpression expression,
Queue<MethodCallExpression> methodCallsQueue)
{
var call = GenerateSafeDereferenceCall(expression.Expression.Type,
expression.Type,
expression.Expression,
p => Expression.PropertyOrField(p, expression.Member.Name));
methodCallsQueue.Enqueue(call);
VisitExpression(expression.Expression, methodCallsQueue);
}
private static void VisitMethodCallExpression(MethodCallExpression expression,
Queue<MethodCallExpression> methodCallsQueue)
{
var call = GenerateSafeDereferenceCall(expression.Object.Type,
expression.Type,
expression.Object,
p => Expression.Call(p, expression.Method, expression.Arguments));
methodCallsQueue.Enqueue(call);
VisitExpression(expression.Object, methodCallsQueue);
}
}
You can use it this way:
var street = person.SafeDereference(d=>d.addressdetails.Street);
street = person.SafeDereference(d=>d.addressdetails[1].Street);
street = person.SafeDereference(d=>d.addressdetails.FirstOrDefault().Street);
var name = person.SafeDereference(d=>d.InvoiceList.FirstOrDefault().Product.Name);
Warning : this is not fully tested, it should work with methods and properties, but probably not with extension methods inside the expression.
Edit : Ok, it can't handle extension methods for now (e.g. FirstOrDefault) but it's still possible to adjust the solution.

You would have to take the expression apart and evaluate each bit in turn, stopping when you got a null result. This wouldn't be impossible by any means, but it would be quite a lot of work.
Are you sure this is less work than just putting explicit null guards in the code?

We definately need a null-safe dereferencing operator in C#, but until then look at this question, which provides a slightly different but also neat solution to the same problem.

Any reason why you couldn't just do the following?
bool result;
result = addressdetails != null && addressdetails.Street != null;
result = addressdetails != null && addressdetails.Count > 1 && addressdetails[1].Street != null;
result = addressdetails != null && addressdetails.FirstOrDefault() != null && addressdetails.FirstOrDefault().Street != null;
result = addressdetails != null && addressdetails.FirstOrDefault() != null && addressdetails.FirstOrDefault().Product != null && addressdetails.FirstOrDefault().Product.Name != null;
I think these simple boolean expressions would be the best way to go, they work because of conditional evaluation... When anding (&&) terms together, the first false term will return false and stop the rest from being evaluated, so you wouldn't get any exceptions doing this.

Though it's not the answer on this exact question, the easiest way I know to achieve the same behaviour is to pass pathes to properties as enumerables of property names instead of call chains.
public static bool HasNull<T, Y>(this T someType, IEnumerable<string> propertyNames)
Then parse those enumerables in a circle or recursively using reflection. There are some disadvantages like loosing intelly sense and static name checking, but very easy to implement, which may overweigh them in some cases.
Instead of writing
person.HasNull(d=>d.addressdetails.FirstOrDefault().Street)
you'll have to write
person.HasNull(new string[] { "addressdetails", "0", "Street" })

I blogged about, it works in VB.NET (I translated to C#, but I didn't test the C# version, check it out).
Checkout: How would you check car.Finish.Style.Year.Model.Vendor.Contacts.FirstOrDefault().FullName for null? :-)
Dim x = person.TryGetValue(
Function(p) p.addressdetail(1).FirstOrDefault().Product.Name)

Related

Identify Func<> parameter in method using reflection

I have a collection of methods, and I'd like to identify any that contain a Func<(,,,)> parameter (ideally through reflection).
This would be simple enough by tagging such parameters with [IsFuncAttribute], but I'd like to avoid that approach if possible.
For example, if I had the following method, how could I reliably determine that the third parameter is a Func<,>?
public T MyMethod<T>(T param1, bool param2, Func<t,bool> param3)
{
// do something
}
Alternatively, being able to identify the third parameter as a delegate with a non void return type would be equally useful.
MethodInfo methodInfo = ...;
ParameterInfo[] parameters = methodInfo.GetParameters();
bool thirdParameterIsFunc =
parameters.Length >= 3 &&
parameters[2].ParameterType.IsGenericType &&
parameters[2].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>));
DotNetFiddle
This is specifically for Func<,>. If you want to match any sort of Func, with any number of parameters, then you'll either need a list of typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), etc, or you'll need to match on the full name of the type.
If you need to match a Func with any number of parameters, as an alternative to explicitly testing against every version of Func (There are 17 of them), you could use something like this extension method (Note that this particular example is specific to .NET Core/.Net 5.0):
public static bool IsAnyFunc(this Type type)
{
int typeParameterCount = type.GenericTypeArguments.Length;
if (typeParameterCount == 0)
{
return false;
}
Type funcType = typeof(Func<>)
.Assembly
.GetTypes()
.FirstOrDefault(t =>
t.Name.StartsWith("Func`")
&& t.GetTypeInfo().GenericTypeParameters.Length == typeParameterCount);
return funcType == null ? false : type.GetGenericTypeDefinition() == funcType;
}
Edit:
Although, if you're going to be making this check frequently, the above may not be performant enough. In which case you may want to explicitly list every possilbe Func. However, you don't actually need to check against them all, if you index them by parameter count:
private static readonly List<Type> FuncTypes = new()
{
typeof(Func<>),
typeof(Func<,>),
typeof(Func<,,>),
typeof(Func<,,,>),
typeof(Func<,,,,>),
typeof(Func<,,,,,>),
typeof(Func<,,,,,,>),
typeof(Func<,,,,,,,>),
typeof(Func<,,,,,,,,>),
typeof(Func<,,,,,,,,,>),
typeof(Func<,,,,,,,,,,>),
typeof(Func<,,,,,,,,,,,>),
typeof(Func<,,,,,,,,,,,,>),
typeof(Func<,,,,,,,,,,,,,>),
typeof(Func<,,,,,,,,,,,,,,>),
typeof(Func<,,,,,,,,,,,,,,,>),
typeof(Func<,,,,,,,,,,,,,,,,>)
};
public static bool IsAnyFunc(this Type type)
{
int typeParameterCount = type.GenericTypeArguments.Length;
if (typeParameterCount < 1 || typeParameterCount > FuncTypes.Count)
{
return false;
}
return type.GetGenericTypeDefinition() == FuncTypes[typeParameterCount - 1];
}

How to build expression tree for Contains<T>

I'm following this SO answer to convert lambda expressions to partial SQL syntax.
However, I have problems parsing the expression for Contains. I added a method:
private bool ParseContainsExpression(MethodCallExpression expression)
{
MemberExpression member = (MemberExpression)expression.Arguments[0];
var methodInfo = typeof(List<int>).GetMethod("Contains", new Type[] { typeof(int) });
//TODO check if list contains value
return false;
}
As I'm totally new to expressions, I don't know from where get the property name and value, and the list that contains the values I want to check against. Where are these properties and values stored within the expression?
Your implementation is quite different from the example answer. You really need to inherit from ExpressionVisitor so that you can properly parse the tree.
Let's take this expression for an example:
var myList = new List<string> { "A" };
Expression<Func<string, bool>> a = (s) => myList.Contains(s);
ParseContainsExpression(a.Body as MethodCallExpression);
private bool ParseContainsExpression(MethodCallExpression expression)
{
expression.Object; //myList
expression.Arguments[0]; //s
return false;
}
Note however, these are still Expressions, they are not actual values yet. You need to invoke the expression to get the values.
However, in our case - myList is actually a ConstantExpression. So we can do this:
((expression.Object as MemberExpression).Expression as ConstantExpression).Value; //myList
Which returns us the original list. Note that it's a field access, because the expression is compiled into a closure, which puts myList as a field in the closure class. As you can see, we have to make a lot of assumptions as to the type of Expression we're handling (that it's a field access and then a constant expression). You really need a fully-fledged visitor implementation to do this properly (which the linked answer describes)
Basically you need to process the Method, Object(expression that represents the instance for instance method calls or null for static method calls) and Arguments(a collection of expressions that represent arguments of the called method) properties of the MethodCallExpression class.
Specifically for Contains, you need to avoid (or process differently if needed) the string.Contains method, and also handle static methods like Enumerable.Contains as well as instance methods like ICollection<T>.Contains, List<T>.Contains etc. In order to get the list values (when possible), you have to find some sort of a constant expression.
Here is a sample:
private bool ParseContainsExpression(MethodCallExpression expression)
{
// The method must be called Contains and must return bool
if (expression.Method.Name != "Contains" || expression.Method.ReturnType != typeof(bool)) return false;
var list = expression.Object;
Expression operand;
if (list == null)
{
// Static method
// Must be Enumerable.Contains(source, item)
if (expression.Method.DeclaringType != typeof(Enumerable) || expression.Arguments.Count != 2) return false;
list = expression.Arguments[0];
operand = expression.Arguments[1];
}
else
{
// Instance method
// Exclude string.Contains
if (list.Type == typeof(string)) return false;
// Must have a single argument
if (expression.Arguments.Count != 1) return false;
operand = expression.Arguments[0];
// The list must be IEnumerable<operand.Type>
if (!typeof(IEnumerable<>).MakeGenericType(operand.Type).IsAssignableFrom(list.Type)) return false;
}
// Try getting the list items
object listValue;
if (list.NodeType == ExpressionType.Constant)
// from constant value
listValue = ((ConstantExpression)list).Value;
else
{
// from constant value property/field
var listMember = list as MemberExpression;
if (listMember == null) return false;
var listOwner = listMember.Expression as ConstantExpression;
if (listOwner == null) return false;
var listProperty = listMember.Member as PropertyInfo;
listValue = listProperty != null ? listProperty.GetValue(listOwner.Value) : ((FieldInfo)listMember.Member).GetValue(listOwner.Value);
}
var listItems = listValue as System.Collections.IEnumerable;
if (listItems == null) return false;
// Do whatever you like with listItems
return true;
}

How to parse expression tree to extract a type condition OfType

I am trying to implement the Queryable interface and I would like to extract the type from the expression.
I have implemented the Queryable using the sample in http://blogs.msdn.com/b/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx.
When I reach the Execute method in my Provider, the expression is :
expression = {value(TestApp.HouseQueryable`1[TestApp.House]).OfType().Where(i => (i.Address == "N.125 Oxford St."))}
The first argument seem to be the type but from there on I am not sure how to extract it from the OfType() method. Can someone help me on this ?
The code to build the queryable and the query provider are the one from the tutorial.
Thanks
Edit: To expand more on my goal, I would like to query from different services depending on the type given. I know that it is not the best way to do it since i will end up having a big IF ELSE in my query provider.
By following the response of Ani, I inherited from ExpressionVisitor and checked for method call to extract the type. I only tested my scenario which is having only one .OfType() and it seems to work.
public class ExpressionTreeModifier : ExpressionVisitor
{
public ExpressionTreeModifier(Expression expression)
{
this.Visit(expression);
}
protected override Expression VisitMethodCall(MethodCallExpression methodCall)
{
var method = methodCall.Method;
if (method.Name == "OfType" && method.DeclaringType == typeof(Queryable))
{
var type = method.GetGenericArguments().Single();
OfType = (Type)type;
}
return base.VisitMethodCall(methodCall);
}
public Type OfType { get;set; }
}
I'm not sure where you're going with this exactly, but to answer what you ask (and nothing more):
IQueryable queryable = ...
var methodCall = queryable.Expression as MethodCallExpression;
if(methodCall != null)
{
var method = methodCall.Method;
if(method.Name == "OfType" && method.DeclaringType == typeof(Queryable))
{
var type = method.GetGenericArguments().Single();
Console.WriteLine("OfType<{0}>", type);
}
}
Not sure how this highly specific bit of code is going to help you write your own query-provider, honestly. Could you expand a bit on your broader goals?

Returning Expression<> using various class properties

I have something like this:
public Expression<Func<Message, bool>> FilterData()
{
switch (this.operatorEnum)
{
case FilterParameterOperatorEnum.EqualTo:
return message => !string.IsNullOrEmpty(message.Body) &&
message.Body
.Equals(this.value, StringComparison.InvariantCultureIgnoreCase);
case FilterParameterOperatorEnum.NotEqualTo:
return message => !string.IsNullOrEmpty(message.Body) &&
!message.Body
.Equals(this.value, StringComparison.InvariantCultureIgnoreCase);
case FilterParameterOperatorEnum.Contains:
return message =>
!string.IsNullOrEmpty(message.Body) &&
message.Body.IndexOf(this.value,
StringComparison.InvariantCultureIgnoreCase) >= 0;
case FilterParameterOperatorEnum.DoesNotContain:
return message =>
!string.IsNullOrEmpty(message.Body) &&
message.Body.IndexOf(this.value,
StringComparison.InvariantCultureIgnoreCase) == -1;
}
}
As you can see this is done on Message.Body
I now what to do the same thing on other string properties on the Message class and I don't want to duplicate all that code.
Is there a way to do that by passing in the property somehow?
Eclude the expression that retrieves the property value into a separate lambda expression:
public Expression<Func<Message, bool>> FilterData(Func<Message, string> retrievePropValueFunc)
In your filter expressions, you can then call that new lambda expression (just showing one as an example):
return message => !string.IsNullOrEmpty(retrievePropValueFunc(message))
&& retrievePropValueFunc(message)
.Equals(this.value, StringComparison.InvariantCultureIgnoreCase);
To get to the Body property, pass message => message.Body to the retrievePropValueFunc parameter; as you see, you can modify this to pass different lambda expressions for the retrieval of other properties just as well.
You can try composing the expression completely manually, which will give you the ability to specify the property name as a string. This isn't a complete solution and it's untested, but it may give you a starting point to see what I mean:
var parameter = Expression.Parameter(typeof(Message), "o");
var getname = Expression.Property(parameter, "Body");
var isnullorempty = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, getname));
var compare = Expression.Equal(getname, Expression.Constant("thisvalue"));
var combined = Expression.And(isnullorempty, compare);
var lambda = Expression.Lambda(combined, parameter);
So you would change your function to accept "Body" as a parameter, and then cast the lambda at the end to:
expression<func<Message, bool>>
I may not have got the syntax for creating the lambda exactly right though.
Just change your function to receive the property instead of the message.
Or the hard way pass one more parameter for the property name and select it using reflection.
Edit just for one option than change for all the options.
public Func<Message, string, bool> FilterData()
{
return (message, propName) =>
{
var prop = message.GetType().GetProperty(propName);
if(prop != null){
var propValue = (string)prop.GetValue(message,null);
return !string.IsNullOrEmpty(propValue) && ...;
}
return false;
};
}
A very quick and dirty approach could be an enum plus some kind of magic:
public enum FilterTarget { Body, AnyOtherProp };
public Expression<Func<Message, bool>> FilterData(FilterTarget filterTarget)
{
string toBeFiltered = string.Empty;
switch(filterTarget)
{
case FilterTarget.Body :
{ toBeFiltered = message.Body; } break;
case FilterTarget.AnyOtherProp :
{ toBeFiltered = message.AnyOtherProp; } break;
default:
{
throw new ArgumentException(
string.Format("Unsupported property {0}", filterTarget.ToString()
);
}
}
switch (this.operatorEnum)
{
case FilterParameterOperatorEnum.EqualTo:
return message => !string.IsNullOrEmpty(toBeFiltered) &&
toBeFiltered.Equals(this.value, StringComparison.InvariantCultureIgnoreCase);
/* CUT: other cases are similar */
}
}
You can make the FilterData method even more fancy letting it accept a params FilterTarget[] thus gaining multi-filtering capabilities (off the top of my head, code not included).
Usage:
var aFilterDataResult = FilterData(FilterTarget.Body);
var anotherFilterDataResult = FilterData(FilterTarget.AnyOtherProp);
...

How to recognize a Lambda MemberExpression of type "field reference"

I have had to find a way to substitute implicit field references in a lambda expression with it's real value. For example :
Expression<Func<TestObject, String>> exp = null;
for (int i = 0; i < 1; i++)
{
exp = t => t.SubObjs[i].TestSTR;
}
Func<TestObject, String> testFunc = exp.Compile();
String testValue = testFunc(myObj);
When inspecting the delegate, you can see this :
{t => t.SubObjs.get_Item(value(testExpression.Program+<>c__DisplayClass4).i).TestSTR}
When calling the delegate outside the for loop, the value of "i" is solved, by reference. But "i" have changed since it's last iteration ("i" == 1 and not 0).
So I build a specific ExpressionVisitor in order to replace the corresponding node with a ConstantExpression :
public class ExpressionParameterSolver : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression node)
{
if (node.ToString().StartsWith("value(") && node.NodeType == ExpressionType.MemberAccess)
{
var index = Expression.Lambda(node).Compile().DynamicInvoke(null);
return Expression.Constant(index, index.GetType());
}
return base.VisitMember(node);
}
}
I don't have found a way other than .StartsWith("value(") in order to detect that the current node is a reference to a field... this kind of node inherits from FieldExpression but this class is internal, and I'm not sure FieldExpression only encapsulate what I consider an "implicit field reference".
So is there a way (an attribute or a method) to explicitly know that a MemberExpression node is an implicit field reference ???
Thanks in advance !!!
and thanks to this stakx post
Just fetch the Member property from the expression and see whether it's a FieldInfo...
If you only want it to be for cases where the class is compiler-generated you could use
if (expression.Member is FieldInfo &&
expression.Member
.DeclaringType
.IsDefined(typeof(CompilerGeneratedAttribute), false))
{
....
}
There can be other reasons why a type might be compiler-generated though. It doesn't sound like a terribly good idea to me.
Can't you just avoid capturing loop variables in your lambda expressions to start with?

Categories

Resources