I have a method for creating a Regex
based Expression
which works fine for direct properties of the relevant entity. So the below work fine for anything like entity.property
public static Expression<Func<T, bool>> CreateRegExExpression<T>(string pattern, string property)
{
var paramObject = Expression.Parameter(typeof(T));
var paramType = Expression.TypeAs(paramObject, typeof(T));
var propertyField = Expression.Property(paramType, property);
var _pattern = Expression.Constant(pattern, typeof(string));
var paramsEx = new Expression[] { propertyField, _pattern };
var methodInfo = typeof(Regex).GetMethod("IsMatch", new Type[] { typeof(string), typeof(string) });
if (!methodInfo.IsStatic || methodInfo == null)
throw new NotSupportedException();
var lamdaBody = Expression.Call(null, methodInfo, paramsEx);
return Expression.Lambda<Func<T, bool>>(lamdaBody, paramObject);
}
However, I have not been able to make this work for a nested property, such as entity.sub_entity.property
as the call to CreateRegExExpression
requires the <T>
class to appropriately return the lamba?
Has anyone got any tips on how to construct the lambda for a nested property dynamically as the below works fine, but I can't seem to work out how to make that recursive using the above function.
Expression<Func<entity, bool>> lambda = e => Regex.Ismatch(e.sub_entity.property, pattern)
If I understand your problem correctly you can allow passing the "path" instead of just property name and then split and iterate it:
static Expression<Func<T, bool>> CreateRegExExpression<T>(string pattern, string property)
{
var paramObject = Expression.Parameter(typeof(T));
var paramType = Expression.TypeAs(paramObject, typeof(T));
var props = property.Split(".");
Expression propertyField = Expression.Property(paramType, props[0]);
foreach (var prop in props.Skip(1))
{
propertyField = Expression.Property(propertyField, prop);
}
var _pattern = Expression.Constant(pattern, typeof(string));
var paramsEx = new Expression[] { propertyField, _pattern };
var methodInfo = typeof(Regex).GetMethod("IsMatch", new Type[] { typeof(string), typeof(string) });
if (!methodInfo.IsStatic || methodInfo == null)
throw new NotSupportedException();
var lamdaBody = Expression.Call(null, methodInfo, paramsEx);
return Expression.Lambda<Func<T, bool>>(lamdaBody, paramObject);
}
With usage like CreateRegExExpression(pattern, "sub_entity.property")
Alternatively if you don't have full path, only "previous" property expression you can use reflection to invoke the method:
var memberReflectedType = previousPropertyField.Member.ReflectedType;
var propFieldType = previousPropertyField.Type;
var makeGenericMethod = typeof(CreateRegExExpressionHolder).GetMethod(nameof(CreateRegExExpression), BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(propFieldType);
var invoke = makeGenericMethod.Invoke(null, new[] { pattern, finalPropName }) as Expression;