So, I am trying to learn how to put together my own expressions, pass objects and compile to retrieve generated result, and I am stuck trying to understand exactly where my object instance goes in all of this.
So this is what I have gotten so far from reading through the code and stepping through
Create your object instance, your expressionstring, and parameters.
T SampleString = "Some String I have";
var operation= "it.Replace(#0, #1)";
var operationParameters = new [] { "e", "CLOWN"};
Create a ParameterExpression object to specify the type of parameter your operation will be performed on
ParameterExpression[] parameters = new ParameterExpression[] { Expression.Parameter(typeof(T), "") };
Using the ExpressionParser class, create the expression you need to be executed against your object there
ExpressionParser parser = new ExpressionParser(parameters, operation, operationParameters );
Called the ExpressionParser Parse method to retrieve the generated Expression, passing it the type of the result you want
var generatedExpression = parser.Parse(typeof(String));
Now call the Expression.Lamba, passing it the generatedExpression, and the item
var StringReplaceresult = Expression.Lambda<Func<T,String> >(generatedExpression , parameters).Compile()(item);
I am not quite sure if the above is correct, or where exactly the issue I am having with it starts. I do know that my Compile fails (5). The message is about not passing in the right number of parameters to the Expression.Lamba method there. But I wonder if that is really where the problem is as, again, I am not sure I get this even 60%, so I would appreciate it is someone would please correct my work above, where necessary.
I'm assuming you're using the Dynamic Linq Query Library described by Scott Guthrie:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
If so, I think you want:
string sampleString = "some string I have";
var operation= "it.Replace(#0, #1)";
var operationParameters = new [] { "e", "CLOWN"};
Expression<Func<string, string>> expr = DynamicExpression.ParseLambda<string, string>(operation, operationParameters);
string result = expr.Compile().Invoke(sampleString);
When I run this in LinqPad the value of result is "somCLOWN string I havCLOWN"
The DynamicExpression.ParseLambda allows you to specify the parameter types as generic type arguments, rather than doing it by explicit creation of a ParameterExpression array as you were doing.
The ParseLambda<> call returns a strongly typed Expression<TDelegate> object and it's Compile() method compiles the underlying lambda expression into executable code and returns it as a delegate of the correct type that can then be invoked. That means the Invoke() returns an object of the correct type(string in this case) rather than an object that has to be cast. So even though you start off with non-strongly-typed code, you get back to type-safety as quickly as possible.
http://msdn.microsoft.com/en-us/library/bb345362.aspx
p.s.
And in the source code I have, ExpressionParser is internal, you naughty boy/girl ;o)
Related
I would like to create the following expression dynamically:
e.Collection.Select(inner => inner.Property)
I created this code to do it, however I have an issue when I execute the expression call, someone knows what I'm doing wrong?
private static Expression InnerSelect<TInnerModel>(IQueryable source, ParameterExpression externalParameter, string complexProperty)
{
// Creates the expression to the external property. // this generates: "e.Collection".
var externalPropertyExpression = Expression.Property(externalParameter, complexProperty);
// Creates the expression to the internal property. // this generates: "inner => inner.Property"
var innerParameter = Expression.Parameter(typeof(TInnerModel), "inner");
var innerPropertyExpression = Expression.Property(innerParameter, "Property");
var innerLambda = Expression.Lambda(innerPropertyExpression, innerParameter);
return Expression.Call(typeof(Queryable), "Select", new [] { typeof(TInnerModel) }, externalPropertyExpression, innerLambda);
}
Error:
No generic method 'Select' on type 'System.Linq.Queryable' is
compatible with the supplied type arguments and arguments. No type
arguments should be provided if the method is non-generic.
So, first off, the primary problem is very simple. As the error message says, you haven't passed enough type arguments to Select. But when you fix that, you'll still have a problem, and that problem will be much harder for you to see and understand.
Let's dig into that.
You wish to represent this as an expression tree:
e.Collection.Select(inner => inner.Property)
Let's begin by rewriting it in its non-extension-method form.
Queryable.Select<A, B>(e.Collection, inner => inner.Property)
Where A is the collection member type and B is the type of Property.
Now, suppose you had this expression in your program. What would it actually do at runtime? It would construct an expression tree for the lambda and pass it to Queryable.Select. That is, it would do something like:
var innerParameter = parameterFactory(whatever);
var lambdaBody = bodyFactory(whatever);
var lambda = makeALambda(lambdaBody, innerParameter);
Queryable.Select<TInnerModel>(e.Collection, lambda);
Right? You with me so far?
Now, suppose we wish to translate this program fragment to an expression tree that could itself be the body of a lambda. That would be:
var theMethodInfoForSelect = whatever;
var receiverE = valueFactory(whatever);
var thePropertyInfoForCollection = whatever;
var theFirstArgument = propertyFactory(receiverE, thePropertyInfoForCollection);
...
Again, with me so far? Now, the crucial question: what is the second argument? It is NOT the value of lambda, which is what you are passing. Remember, what we are doing here is constructing an expression tree which represents the code that the compiler is generating for that thing, and the expression tree that is in lambda is not that. You're mixing levels!
Let me put it this way: the compiler is expecting "add one and three". You are passing 4. Those are very different things! One of them is a description of how to obtain a number and the other one is a number. You are passing an expression tree. What the compiler is expecting is a description of how to obtain an expression tree.
So: do you have to now write code that generates expression trees for all of lambda's construction code? Thank goodness no. We provided you a handy way to turn an expression tree into a description of how to produce an expression tree, which is the Quote operation. You need to use it.
So, what is the right sequence of events that you need to do to build your expression tree? Let's walk through it:
First, you'll need a ParameterExpression of the type of e, which you already have in hand. Let's suppose that is:
ParameterExpression eParam = Expression.Parameter(typeof(E), "e");
Next, you will need a method info for the Select method. Let's suppose you can correctly get that.
MethodInfo selectMethod = whatever;
That method takes two arguments, so let's make an array of argument expressions:
Expression[] arguments = new Expression[2];
You'll need a property info for your Collection property. I assume you can get that:
MethodInfo collectionGetter = whatever;
Now we can build the property expression:
arguments[0] = Expression.Property(eParam, collectionGetter);
Super. Next we need to start building that lambda. We need a parameter info for inner:
ParameterExpression innerParam = Expression.Parameter(typeof(Whatever), "inner");
We'll need a property info for Property, which I assume you can get:
MethodInfo propertyGetter = whatever;
Now we can build the body of the lambda:
MemberExpression body = Expression.Property(innerParam, propertyGetter);
The lambda takes an array of parameters:
ParameterExpression[] innerParams = { innerParam };
Build the lambda from the body and the parameters:
var lambda = Expression.Lambda<Func<X, int>>(body, innerParams);
Now the step you missed. The second argument is the quoted lambda, not the lambda:
arguments[1] = Expression.Quote(lambda);
Now we can build the call to Select:
MethodCallExpression callSelect = Expression.Call(null, selectMethod, arguments);
And we're done.
Give someone an expression tree and you give them an expression tree for a day; teach them how to find expression trees themselves and they can do it for a lifetime. How did I do that so fast?
Since I wrote the expression tree code generator, I had some immediate familiarity with the problem that you were likely to have. But that was ten years ago, and I did not do the above entirely from memory. What I did was I wrote this program:
using System;
using System.Linq.Expressions;
public interface IQ<T> {}
public class E
{
public IQ<X> C { get; set; }
}
public class X
{
public int P { get; set; }
}
public class Program
{
public static IQ<R> S<T, R>(IQ<T> q, Expression<Func<T, R>> f) { return null; }
public static void Main()
{
Expression<Func<E, IQ<int>>> f = e => S<X, int>(e.C, c => c.P);
}
}
Now I wished to know what code was generated by the compiler for the body of the outer lambda, so I went to https://sharplab.io/, pasted in the code, and then clicked on Results --> Decompile C#, which will compile the code to IL and then decompile it back to human-readable C#.
This is the best way I know of to quickly understand what the C# compiler is doing when it builds an expression tree, regardless of whether you know the compiler source code backwards and forwards. It's a very handy tool.
I have a expression getter like that:
var expression = () => SomeInstance.Nr;
It is passed into a method:
public void AddExpression<T>(Expression<Func<T>> func)
Now I would like to convert that generic expression to
Expression<Func<object>>
I'm not quite sure if I can even do that. I tried something like this:
var converted = Expression.Convert(func, typeof(object));
var objectExpression = Expression.Lambda<Func<object>>(Expression.Call(converted.Method), func.Parameters);
But when I call
var number = objectExpression.Compile()();
It won't return the property value.
The code can be tested here:
http://volatileread.com/utilitylibrary/snippetcompiler?id=25062
Update:
It seems that the invoke is wrapped a second time:
var converted = Expression.Convert(func, typeof(object));
var objectExpression = Expression.Lambda<Func<object>>(Expression.Call(converted.Method), func.Parameters);
var anotherDelegate = objectExpression.Compile().Invoke(); // would have expected the value here
var value = ((Delegate)anotherDelegate).DynamicInvoke(); // this now does return the value
Don't use Expression.Call on delegates - that's only there to call methods. Instead, you want to use Expression.Invoke, which is specifically there to invoke delegates. Also, the key to doing expression trees is wrapping - invoke the inner delegate, convert the result, and wrap this in a lambda:
Expression<Func<int>> inputExpression = () => 42;
var newLambda =
Expression.Lambda<Func<object>>
(
Expression.Convert
(
Expression.Invoke(inputExpression),
typeof(object)
)
);
Console.WriteLine(newLambda.Compile()()); // Prints 42.
newLambda is Expression<Func<object>> and invoking it gives you 42, as you'd expect.
And of course, this makes it rather easy to make this an extension method (although you probably want to use templates to generate all the different Func<...> overloads if you need them).
Do note that this is only going to work if whatever LINQ provider you're using actually supports Invoke - in this case, it's not a problem because the lambda compiler can handle it, but if you need to use something like this with e.g. EntityFramework, you'll need to take a slightly different approach - you'll need to unwrap the inner lambda, convert the body of the inner lambda, and then wrap it again in another lambda. For a parameter-less expression, this is rather easy:
Expression<Func<int>> inputExpression = () => 42;
var newLambda =
Expression.Lambda<Func<object>>
(
Expression.Convert(inputExpression.Body, typeof(object))
);
Console.WriteLine(newLambda.Compile()()); // Prints 42.
Also, for completeness, note that this only works if the inner expression is really a constant expression, and not a quote - but if you needed quoted nested expressions, you probably wouldn't be asking this question :D
I have a table that's mapped, but after compile additional columns can be added or removed from the table. I'm trying to come up with a linq query that will take those new columns into account. In this scenario, I want to order by one of those dynamic columns. This is what I have so far.
var queryableData = dc.wf_task_ext_attributes.AsQueryable();
ParameterExpression pe = Expression.Parameter(typeof(DateTime), "ExtValue105");
// The next line is where it fails
MethodCallExpression orderByCallExpression = Expression.Call(
typeof(Queryable),
"OrderBy",
new Type[] { queryableData.ElementType, queryableData.ElementType },
queryableData.Expression,
Expression.Lambda<Func<DateTime, DateTime>>(pe, new ParameterExpression[] { pe }));
IQueryable<string> results = queryableData.Provider.CreateQuery<string>
(orderByCallExpression);
It's failing with the following message:
No generic method 'OrderBy' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.
What am I doing wrong?
Is queryableData of type IQueryable<DateTime>? Seems not to be since you are calling CreateQuery<string>.
Your call to Expression.Call seems to assume that this is an IQueryable<DateTime>. Make sure that it is.
You can find out how to correctly build a LINQ query by hard-coding the query and then decompiling the resulting assembly.
Your code tries to create something like Queryable.OrderBy(queryableData.Expression, ExtValue105 => ExtValue105). I have no idea why would you expect that to work.
If I understand your question correctly, you need to dynamically create an expression like attribute => attribute.ExtValue105 and then you can use that to call OrderBy().
The code could look something like this (assuming queryableData is IQueryable<Attribute>):
var parameter = Expression.Parameter(typeof(Attribute), "attribute");
var property = Expression.Property(parameter, "ExtValue105");
var lambda = Expression.Lambda(property, parameter);
IQueryable<Attribute> results =
Queryable.OrderBy(queryableData, (dynamic)lambda);
You could use queryableData.Provider.CreateQuery() manually to avoid the dynamic call, but that would be more complicated.
I need to create a System.Linq.Expressions.Expression that call a dynamic object. The dynamic object can be an ExpandoObject or any other IDynamicMetaObjectProvider.
Consider the following test:
var myInstance = DateTime.Now;
var methodInfo = myInstance.GetType().GetMethod("ToUniversalTime");
var methodCallExpression = Expression.Call(Expression.Constant(myInstance), methodInfo);
var expression = Expression.Lambda(methodCallExpression);
Assert.AreEqual(myInstance.ToUniversalTime(), expression.Compile().DynamicInvoke());
I need to create an equivalent expression when myInstance is declared like (just as an example):
dynamic myInstance = new ExpandoObject();
myInstance.MyMethod = new Func<string>(() => "hello world");
I suppose that I need to use Expression.Dynamic method (see MSDN). But I don't known how to use it. I have tried to search on google but the only examples that I have found use the Microsoft.CSharp.RuntimeBinder.Binder class (see MSDN) that cannot be officially used:
This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.
Using Microsoft.CSharp.RuntimeBinder.Binder I can write the code below:
dynamic myInstance = new ExpandoObject();
myInstance.MyMethod = new Func<string>(() => "hello world");
var binder = Binder.InvokeMember(
CSharpBinderFlags.None,
"MyMethod",
null,
this.GetType(),
new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant, null) });
var methodCallExpression = Expression.Dynamic(binder, typeof(object), Expression.Constant(myInstance));
var expression = Expression.Lambda(methodCallExpression);
Assert.AreEqual(myInstance.MyMethod(), expression.Compile().DynamicInvoke());
It this solution correct?
Here is the catch: from my understanding, there is no meaning in making a dynamic call without some kind of Binder object.
The binder object represents the rules that are followed for dynamic name resolution:
Should the match be case-sensitive?
How should method overloads be resolved?
What to do if the object is a non-dynamic object?
What fallbacks do you use?
In other words, the Binder object represents the semantics of the calling "language", while IDynamicMetaObjectProvider represents the semantics of the called object.
So, yes, we are not supposed to use the CSharp Binder object. That can be felt especially when some issues happen that can only be worked around by using the object's internals. However, the alternative is simply to use another, non-framework-provided, Binder implementation.
dynamic x = typeof("<<MethodName>>")
.GetMethod("ToUniversalTime")
.Invoke(<<Type Of Object>>, new object[] { [Parameter1,]
[Parameter2,....] });
in this code "Type" instead from which type of object you have to call method...
specify your method name instead of "MethodName"
and lastly your object instead of "Type of Object"
and if there is no parameter then pass empty array...other wise pass instead of "parameter1,2,and so on.
If anyone is very familar with the Linq.Dynamic namespace I could use some help -- couldn't find any indepth resources on the internet.
Basically I'm using DynamicExpression.ParseLambda to create an expression where the type is not known at compile time,
public Expression GetExpression(Type t, List<QueryFilter> filters)
{
// pseudo code
// extracts a string representation of the query as 'expressionString'
return DynamicExpression.ParseLambda(t, typeof(Boolean), expressionString, values);
}
Where a QueryFilter is:
public class QueryFilter
{
string propertyName;
ExpressionType operationType;
object value;
}
Which represents a simple binary function like "Age > 15" or something.
This is how the 'GetExpression' function works, it takes 2 types -- one that is the input type and one that is the output type, and ultimately generates what would normally be created with a Func delegate. It also takes a string that represents the query and a params object[] of values, which are 'expressionString' and 'values' above, respectively.
However I am having trouble executing the dynamic expression in LINQ-to-SQL, using a DataContext generated from SqlMetal (.dbmc file).
DatabaseContext db = new DatabaseContext(connectionString);
var filter = DynamicExpressionBuilder.
GetExpression(typeof(SysEventLogT), sysEventFilters)
var query = db.SysEventLogT.Where(filter);
Produces the following error,
System.Data.Linq.Table<DBReporting.Linq.Data.SysEventLogT>
does not contain a definition for 'Where' and the best extension method overload
System.Linq.Dynamic.DynamicQueryable.Where<T>(System.Linq.IQueryable<T>, string, params object[])
has some invalid arguments.
I know that my DataContext instance actually treats the sql tables as properties...do I need to reflect with GetProperty() somehow for this to work? Or perhaps I need to create another .Where extension?
Your GetExpression is returning an Expression type - the DynamicQueryable.Where method, when used as an extension method, expects a string as the first parameter.
You need your call to Where to look like this:
var query = db.SysEventLogT.Where("Age > #0", 15);
Also, you could try the following, just to be explicit:
var query = db.SysEventLogT.AsQueryable().Where("Age > #0", 15);
Note that if easier, you can build a sting containing the full filter and not use the params object[] parameter at all:
var query = db.SysEventLogT.AsQueryable().Where("Age > 15");