Utilizing Funcs within expressions? - c#

Background
I have an example of a test that passes but an error that happens down the pipeline and I'm not sure why. I'd like to figure out what's going on but I'm new to Expression construction and don't want to make any assumptions.
This is for a search filtering mechanism. It uses ServiceStack's PredicateBuilder implementation. I essentially have a list of values that I pass in, and I want it to construct an expression tree. I had previously done this just with Func<T<bool>> but realized that I needed to wind up with Expression<Func<T<bool>>>. Bummer.
The Goal
Search filters built from Re-usable search filter types, which built out of Funcs and Expressions that allows me to pass in a field name from an object along with values I should match on and wind up with something that we can run a Where() statement against.
The Code / Issue
The generic "nullable bool" filter I'm trying -- sets up the acceptable items and returns a func that is meant to help filter:
public class NullableBoolFilter : IGenericSearchFilter<bool?>
{
public Func<bool?, bool> GetFilterFunc(string valuesToProcess)
{
var acceptableValues = new List<bool?>();
if (string.IsNullOrWhiteSpace(valuesToProcess))
{
// all values acceptable
acceptableValues = new List<bool?>{true, false, null};
}
else
{
if (!valuesToProcess.Contains("0") && !valuesToProcess.Contains("1"))
{
throw new ArgumentException("Invalid Nullable boolean filter attribute specified");
}
if (valuesToProcess.Contains("0"))
{
acceptableValues.Add(false);
}
if (valuesToProcess.Contains("1"))
{
acceptableValues.Add(true);
}
}
Func<bool?, bool> returnFunc = delegate(bool? item) { return acceptableValues.Any(x=>x == item); };
return returnFunc;
}
}
Then I have another filter, which inherits from the NullableBoolFilter and attempts to use the Func:
public class ClaimsReportIsMDLFilter : NullableBoolFilter, ISearchFilter<vSEARCH_ClaimsReport>
{
public Expression<Func<vSEARCH_ClaimsReport, bool>> GetExpression(string valuesToProcess)
{
var theFunc = base.GetFilterFunc(valuesToProcess);
Expression<Func<vSEARCH_ClaimsReport, bool>> mdlMatches = item => theFunc(item.IsMDL);
var predicate = PredicateBuilder.False<vSEARCH_ClaimsReport>();
predicate = predicate.Or(mdlMatches);
return predicate;
}
}
The following test passes:
public class ClaimsReportIsMDLFilterTests
{
// ReSharper disable InconsistentNaming
private readonly vSEARCH_ClaimsReport ItemWithMDL = new vSEARCH_ClaimsReport { IsMDL = true };
private readonly vSEARCH_ClaimsReport ItemWithoutMDL = new vSEARCH_ClaimsReport { IsMDL = false };
private readonly vSEARCH_ClaimsReport ItemWithNullMDL = new vSEARCH_ClaimsReport { IsMDL = null };
// ReSharper restore InconsistentNaming
[Fact]
public void WithSearchValueOf1_HidesNonMDLAndNull()
{
var sut = this.GetCompiledExpressionForValues("1");
sut.Invoke(ItemWithMDL).Should().BeTrue();
sut.Invoke(ItemWithoutMDL).Should().BeFalse();
sut.Invoke(ItemWithNullMDL).Should().BeFalse();
}
private Func<vSEARCH_ClaimsReport, bool> GetCompiledExpressionForValues(string searchValue)
{
return new ClaimsReportIsMDLFilter().GetExpression(searchValue).Compile();
}
}
The Problem
When I actually attempt to run this, I receive the error:
variable 'param' of type 'vSEARCH_ClaimsReport' referenced from scope '', but it is not defined
It makes sense to me why this might occur -- at the time it's evaluated, I don't have a real object to pass into the Func. However, I'm confused as to why my tests might pass but this doesn't in actual usage.
Questions
Why might my tests pass but I still receive this error?
How the heck should I begin trying to fix this?
Is there a remotely easy way to take that Func and turn it into an Expression that I can pass a field into?
Do I need to abandon the generic filter idea and have each class manually add expressions to the PredicateBuilder based on input passed in? That's doable, but it seems like the work could be reduced more.

Why might my tests pass [...]
Because your test is simply compiling the expression down into the code that it represents and invoking it. It doesn't need to actually parse the expression tree and look at what the code it represents is doing, it just runs it and ensures that the output is right.
Why might [...] I still receive this error?
Because when you're actually using it, it's not just executing the code; rather it is looking through the expression tree to try to determine what the code is doing so that it can be translated into something else, not so that it can be run as C# code.
Your expression is doing nothing but calling a delegate. There is no way for someone traversing the expression tree to see inside the delegate and know what it's doing. Knowing that you're calling another method isn't something that can be translated into another language.
How the heck should I begin trying to fix this?
You need to generate an Expression from the start, rather than generating a Func and then just creating an Expression that calls it.
Is there a remotely easy way to take that Func and turn it into an Expression that I can pass a field into?
No. You'd need to pull out the IL code of the function, decompile that into C# code, then build up Expression objects to represent that code. That's pretty much just not going to happen.
You're pretty much going to need to have GetFilterFunc return an Expression, to get this to work. Fortunately, this is quite easy to do, given what you have. You simply need to change the method signature and to replace the last two lines with the following:
return item => acceptableValues.Any(x => x == item);
And voila. The lambda can be compiled into an Expression object, rather than a delegate, based on context, so if the return type of the method is an Expression<Func<bool?,bool>> that's what you'll get.
Now, to use this in GetExpression. First off, the PredicateBuilder isn't really doing anything. Adding an OR FALSE to your expression changes nothing meaningful about it. All of that can go. All that leaves us with is using an Expression<Func<bool?,bool>> and changing it into an Expression<Func<vSEARCH_ClaimsReport, bool>> by pulling out a boolean property. To do this is a bit more work for expressions than for delegates. Rather than just invoking the expression, we need to do a tad more work to compose them. We'll want to write a method to do this operation:
public static Expression<Func<TFirstParam, TResult>>
Compose<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
And this relies on the use of the following method to replace all instances of one expression with another:
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
What this is doing is replacing all instances of the second expression's parameter with the body of the first expression, effectively inlining that expression into the second. The rest is simply replacing all of the parameters with a new single parameter and wrapping it back up into a lambda.
Now that we have that, our method is quite easy:
public Expression<Func<vSEARCH_ClaimsReport, bool>> GetExpression(
string valuesToProcess)
{
Expression<Func<vSEARCH_ClaimsReport, bool?>> selector =
item => item.IsMDL;
return selector.Compose(base.GetFilterFunc(valuesToProcess));
}

Related

Extension method in where clause in linq to Entities

In linq to Entities we needed a method that works like "sql like". We have implemented our own extension method to IQueryable, because contains method not work for us because doesn't accept patterns like '%a%b%'
The created code is:
private const char WildcardCharacter = '%';
public static IQueryable<TSource> WhereLike<TSource>(this IQueryable<TSource> _source, Expression<Func<TSource, string>> _valueSelector, string _textSearch)
{
if (_valueSelector == null)
{
throw new ArgumentNullException("valueSelector");
}
return _source.Where(BuildLikeExpressionWithWildcards(_valueSelector, _textSearch));
}
private static Expression<Func<TSource, bool>> BuildLikeExpressionWithWildcards<TSource>(Expression<Func<TSource, string>> _valueSelector, string _textToSearch)
{
var method = GetPatIndexMethod();
var body = Expression.Call(method, Expression.Constant(WildcardCharacter + _textToSearch + WildcardCharacter), _valueSelector.Body);
var parameter = _valueSelector.Parameters.Single();
UnaryExpression expressionConvert = Expression.Convert(Expression.Constant(0), typeof(int?));
return Expression.Lambda<Func<TSource, bool>> (Expression.GreaterThan(body, expressionConvert), parameter);
}
private static MethodInfo GetPatIndexMethod()
{
var methodName = "PatIndex";
Type stringType = typeof(SqlFunctions);
return stringType.GetMethod(methodName);
}
This works correctly and the code is executed entirely in SqlServer, but now we would use this extension method inside where clause as:
myDBContext.MyObject.Where(o => o.Description.Like(patternToSearch) || o.Title.Like(patterToSerch));
The problem is that the methods used in the where clause have to return a bool result if is it used with operators like '||' , and I don't know how to make that the code I have created returns a bool and keep the code executed in sqlserver. I suppose that I have to convert the returned Expression by BuildLinqExpression method to bool, but I don't know how to do it
To sum up! First of all it's possible to create our own extensiond methods in Linq to Entities that execute the code in SqlServer? if this is possible how I have to do it?
Thanks for your help.
No, you cannot educate EF to process your custom extension methods, even though you have code that builds expressions that would be usable to EF.
Either:
use the SqlFunctions methods directly in your EF Where expression
use an ExpressionVisitor to combine multiple expressions into a composite (OrElse / AndAlso) expression (note this won't help you have code like you want, but it will let you use your two methods and perform a || on them - it will look complex, though)
The first is simpler and clearer.
Answered here: https://stackoverflow.com/a/10726256/84206
His code: http://pastebin.com/4fMjaCMV
Allows you to tag an extension method as [Expandable] and so long as the expression it returns works with linq2entities, it will replace your function call with the inner expression. Note that inline lambdas give errors, so I had to declare them as local variables or static variable such as the IsCurrent variable here:
static Expression<Func<PropertyHistory, bool>> IsCurrent = (p) => p.Starts <= DateTime.Now;
[ExpandableMethod]
public static IQueryable<PropertyHistory> AsOf(this IQueryable<PropertyHistory> source)
{
return source.Where(IsCurrent);
}

Get actual return type from a Expression<Func<T, object>> instance

I have a method that accepts a Expression<Func<T, object>> instance. I want to get at the actual data type being returned by a specific expression instance, rather than object.
I can get it to work for direct property references, so if I pass in the expression x => x.IntegerProperty I can get a Type reference for an integer. This approach requires converting it to a MemberExpression.
However, I can't get it to work for arbitrary expressions. For instance, if the expression is x => x.IntegerProperty.ToString() I want to get a Type reference for a string. I can't compile this to a MemberExpression, and if I just .Compile() it and check the return type I get "object".
How can I look at the specific expression instance and derive the actual return type?
Something like this might do the trick. It probably doesn't cover every possibility, but it's a start.
public static Type GetObjectType<T>(Expression<Func<T, object>> expr)
{
if ((expr.Body.NodeType == ExpressionType.Convert) ||
(expr.Body.NodeType == ExpressionType.ConvertChecked))
{
var unary = expr.Body as UnaryExpression;
if (unary != null)
return unary.Operand.Type;
}
return expr.Body.Type;
}
While not impossible, this is particularly difficult. It would require walking the expression tree and doing some potentially complex logic. For example, what would you want to see if I passed in the following expression?
Func<bool, object> expr = switch => switch ? 1 : "False";
This method could either return an int or a string.
Now, you might be able to make more headway by offloading some of this logic on the compiler. You could change your method parameter from Func<T, object> to Func<T, TReturn> and use typeof(TReturn) within the method to determine what the compiler decided the return type of the expression was.
Of course, in the case of my example, you'll still be working against object. But, your example of x => x.IntegerProperty.ToString() will yield string, which is what you're looking for.
Bit of a cheeky way (and it involves actually invoking the Func), but you can do this:
using System;
class Program
{
static Func<T,object> MakeFunc<T>()
{
return x => 23;
}
static Type GetReturnType<T>(Func<T,object> f)
{
return f(default(T)).GetType();
}
static void Main(string[] args)
{
Type t = GetReturnType(MakeFunc<string>());
Console.WriteLine(t);
}
}
It's not guaranteed to work in all situations, I should add - particularly if the default(T) isn't a valid parameter to the Func. But it's a potential starting point at least.

Dynamically get the result of a Func<T,bool> invocation

I am trying to serialize something based upon meeting particular criteria.
To this end my original hope was to use attributes containing a lambda expression on an object's properties.
However, as this cannot be done I've settled for having a Func<T,bool> member within the class and passing the type (or first parameter type) and name of this Func through the property attribute. E.g.:
Func<SomeObject, bool> func = (p => p.Value == 4);
[FuncAtt(typeof(SomeObject), "func")]
public SomeObject PropertyName { get; set;}
In my serializer I need to call this Func<T, bool>.
Let's assume I have a Type t which is equal to typeof(SomeObject) in this case, or more abstractly, typeof(T). I can also get the Func<T,bool> itself, but only through reflection as an object.
My naive approach is something along these lines:
object func = typeof(MyClass).GetField(attribute.FuncName).GetValue(MyClassInstance);
Type funcType = typeof(Func<,>).MakeGenericType(attribute.Type, typeof(bool));
ParameterExpression p = Expression.Parameter(attribute.Type, objectToSerialize);
LambdaExpression l = Expression.Lambda(funcType, func, p); /* Won't work */
But this leads to the problem of casting a lambda to a delegate which is apparently erroneous.
I tried this in place of 'func':
(Expression)((Action)(() => func))
But that relies on func being a method call not a lambda.
So, can anyone point me in the right direction?
You can just do something like this, without need for expressions:
public static class Test
{
public static Predicate<int> func = s => s > 20;
}
and to get the value:
private void Form1_Load(object sender, EventArgs e)
{
var a = typeof(Test).GetField("func");
bool validates = ((Predicate<int>)a.GetValue(null)).Invoke(100);
}
edit to get the value without knowing the type:
bool validates = (bool)((Delegate)a.GetValue(null)).DynamicInvoke(100);
I think you can use Compile method of a lambda expression to cast it to a delegate.
here's what I found on MSDN:
The Expression<(Of <(TDelegate>)>)
type provides the Compile method,
that compiles the code represented by
the expression tree into an executable
delegate. This executable code is
equivalent to the executable code that
would have been generated had the
lambda expression been assigned to a
delegate type originally.
Here you can find it.
Not sure this is working sample, but this is the way:
// not sure what are you doing in this line, but assume it should return
// a method name specified in the attribute, e.g. "func" in your example.
// Also "func" must be a method (static one in my example) of SomeObject class
String funcname = typeof(MyClass).GetField(attribute.FuncName).GetValue(MyClassInstance);
ParameterExpression param = Expression.Parameter(typeof(SomeObject), "p");
MethodCallExpression call = Expression.Call(SomeObject, funcname, new Type[] { typeof(SomeObject), typeof(Boolean) }, param);
LambdaExpression lambda = Expression.Lambda<Func<SomeObject, Boolean>>(call, param);
now you can call the "func" method like this:
Boolean result = lambda.Compile()(SomeObjectInstance);

Reading a property value with a lambda expression

I'm writing a file generic block for my application and started with using Lambda expressions for managing my rule sets for block generation to avoid the pitfalls of magic strings, configuration hell etc.
Inside my mapping class I have lines similar to:
Map(x => x.Name).Length(20).PadLeft(true).PaddingChar("#");
This works fine and isn't where my question dwells, where I setup saving my information about the expression is in the Map method:
public override IPropertyMap Map(Expression<Func<T, object>> expression)
{
var propertyMap = new FixedLengthPropertyMap
{
//Length = 20,
//PaddingCharacter = " ",
PadLeft = false,
PropertyInfo = ReflectionHelper.GetProperty(expression)
};
_properties.Add(propertyMap);
return propertyMap;
}
_properties is just a List<IPropertyMap> that stores my info where my question from what is the best way to have a real object's data be read from the properties currently I came up with something similar to this:
var map = new AgentMap();
var agent = new Agent {Name = "Bob"};
string output = map.Write(agent);
public override string Write<T>(T agent)
{
var initial = _properties[0];
return initial.PropertyInfo.GetValue(agent, null) as string;
}
Is there a better way than using the GetValue method since earlier on I'm using an expression tree?
I don't see why you really need to use expression trees at all. Just make the Map method take a Func<T, object> and store that:
public override IPropertyMap Map(Func<T, string> fetcher)
{
var propertyMap = new FixedLengthPropertyMap
{
//Length = 20,
//PaddingCharacter = " ",
PadLeft = false,
Delegate = fetcher // Delegate is of type Delegate
};
_properties.Add(propertyMap);
return propertyMap;
}
Then:
public override string Write<T>(T agent)
{
var initial = _properties[0];
Func<T, string> fetcher = (Func<T, string>) initial.Delegate;
return fetcher(agent);
}
Is there any reason you particularly wanted to know the property and use an expression tree?
In part, it depends on what your scenario is. The "simple" answer is to just compile the expression and invoke it, but that has a potential performance impact if you are doing it in a tight loop (passing a delegate would be a lot quicker).
I'm not sure whether if would apply in this particular case (because of the agent), but to avoid doing too much expression compilation, you can look for simple scenarios and read the value directly from the expression tree; a little bit of PropertyInfo/FieldInfo is going to be quicker than compiling it...
For more, look at TryEvaluate here, and how it is used with Compile as a backup strategy (although you have the advantage of a known delegate type).

What's the best way to define & access selected properties in C#?

From my recent question, I try to centralize the domain model by including some silly logic in domain interface. However, I found some problem that need to include or exclude some properties from validating.
Basically, I can use expression tree like the following code. Nevertheless, I do not like it because I need to define local variable ("u") each time when I create lambda expression. Do you have any source code that is shorter than me? Moreover, I need some method to quickly access selected properties.
public void IncludeProperties<T>(params Expression<Func<IUser,object>>[] selectedProperties)
{
// some logic to store parameter
}
IncludeProperties<IUser>
(
u => u.ID,
u => u.LogOnName,
u => u.HashedPassword
);
Thanks,
Lambdas are great for many scenarios - but if you don't want them, perhaps simply don't use them? I hate to say it, but simple strings are tried and tested, especially for scenarios like data binding. If you want fast access, you could look at HyperDescriptor, or there are ways of compiling a delegate to the property accessors, or you can build an Expression from the string and compile it (including a cast to object if you want a known signature, rather than calling the (much slower) DynamicInvoke).
Of course, in most cases even crude reflection is fast enough, and isn't the bottleneck.
I suggest starting with the simplest code, and check it is actually too slow before worrying about it being fast. If it isn't too slow, don't change it. Any of the above options would work otherwise.
Another thought; if you are using Expression, you could do something like:
public void IncludeProperties<T>(
Expression<Func<T,object>> selectedProperties)
{
// some logic to store parameter
}
IncludeProperties<IUser>( u => new { u.ID, u.LogOnName, u.HashedPassword });
and then take the expression apart? A bit tidier, at least... here's some sample code showing the deconstruction:
public static void IncludeProperties<T>(
Expression<Func<T, object>> selectedProperties)
{
NewExpression ne = selectedProperties.Body as NewExpression;
if (ne == null) throw new InvalidOperationException(
"Object constructor expected");
foreach (Expression arg in ne.Arguments)
{
MemberExpression me = arg as MemberExpression;
if (me == null || me.Expression != selectedProperties.Parameters[0])
throw new InvalidOperationException(
"Object constructor argument should be a direct member");
Console.WriteLine("Accessing: " + me.Member.Name);
}
}
static void Main()
{
IncludeProperties<IUser>(u => new { u.ID, u.LogOnName, u.HashedPassword });
}
Once you know the MemberInfos (me.Member in the above), building your own lambdas for individual access should be trivial. For example (including a cast to object to get a single signature):
var param = Expression.Parameter(typeof(T), "x");
var memberAccess = Expression.MakeMemberAccess(param, me.Member);
var body = Expression.Convert(memberAccess, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(body, param);
var func = lambda.Compile();
Here's the shortest expression I can come up with:
public static void IncludeProperties(Expression<Action<IUser>> selectedProperties)
{
// some logic to store parameter
}
public static void S(params object[] props)
{
// dummy method to get to the params syntax
}
[Test]
public void ParamsTest()
{
IncludeProperties(u => S(
u.Id,
u.Name
));
}

Categories