Say I have some function like so
public string TestValue(string hello, Guid world)
{
return hello + world;
}
Assuming that objectParams is a dictionary of object Dictionary<string, object> that map the parameter name to the value, I'm currently matching the parameter values to the method name like so:
var method = this.GetType().GetMethod("TestValue");
var methodParameters = method.GetParameters();
var paramMatcher = (from paramValue in objectParams
from methodParam in methodParameters
where param.Key == clrParam.Name
select (name: clrParam.Name,
type: clrParam.ParameterType,
value: paramValue.Value));
I then build the expression to call the method TestValue like so, but this is the part I'm having trouble with.
var paramExpress = (from param in paramMatcher
select Expression.Assign(Expression.Parameter(param.type, param.name), Expression.Constant(param.value)));
Func<object> result = Expression.Lambda<Func<object>(Expression.Call(Expression.Constant(this),
method, paramExpress)).Compile();
var res = result.Invoke(); //should return 'somestringxxxxxxx-xxxx...etc'
The issue is that I can't guarantee that the parameter values are in call order so I want to rely on the name of the parameters to call. I'm not sure on how to assign the constant values to their parameter expressions properly. Running this code results in the exception System.InvalidOperationException: 'variable 'hello' of type 'System.String' referenced from scope '', but it is not defined' when compiling the lambda.
Expression.Assign is a binary operation, so the variable in the left part takes a new value calculated in the right part of expression.
On these lines:
var paramExpress = (from param in paramMatcher
select Expression.Assign(Expression.Parameter(param.type, param.name),
Expression.Constant(param.value, param.type)));
Func<object> result = Expression.Lambda<Func<object>(Expression.Call(Expression.Constant(this),
method, paramExpress)).Compile();
you've received and just didn't used actual parameters values, presented in the right parts of binary expressions.
Solution:
public class C
{
public string TestValue(string hello, Guid world)
{
return hello + world;
}
public string Execute()
{
var objectParams = new Dictionary<string, object>()
{
{"hello", "somestring"},
{"world", Guid.NewGuid()}
};
var method = this.GetType().GetMethod("TestValue");
var methodParameters = method.GetParameters();
var paramMatcher = (from paramValue in objectParams
from methodParam in methodParameters
where paramValue.Key == methodParam.Name
orderby methodParam.Position // <-- preserves original order
select (name: methodParam.Name,
type: methodParam.ParameterType,
value: paramValue.Value));
var paramExpress = (from param in paramMatcher
select Expression.Assign(Expression.Parameter(param.type, param.name),
Expression.Constant(param.value, param.type)));
var values = paramExpress.Select(v => v.Right); // !!!
Func<string> result = Expression.Lambda<Func<string>>(Expression.Call(Expression.Constant(this),
method, values)).Compile();
return result.Invoke(); // returns "somestringxxxxxxx-xxxx..."
}
}
Related
In C# 3.0 you can use Expression to create a class with the following syntax:
var exp = Expression.New(typeof(MyClass));
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();
But how do you use Expression to create an Anonymous class?
//anonymousType = typeof(new{ Name="abc", Num=123});
Type anonymousType = Expression.NewAnonymousType??? <--How to do ?
var exp = Expression.New(anonymousType);
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();
You're close, but you have to be aware that anonymous types don't have default constructors. The following code prints { Name = def, Num = 456 }:
Type anonType = new { Name = "abc", Num = 123 }.GetType();
var exp = Expression.New(
anonType.GetConstructor(new[] { typeof(string), typeof(int) }),
Expression.Constant("def"),
Expression.Constant(456));
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();
Console.WriteLine(myObj);
If you don't have to create many instances of this type, Activator.CreateInstance will do just as well (it's faster for a few instances, but slower for many). This code prints { Name = ghi, Num = 789 }:
Type anonType = new { Name = "abc", Num = 123 }.GetType();
object myObj = Activator.CreateInstance(anonType, "ghi", 789);
Console.WriteLine(myObj);
You can avoid using DynamicInvoke which is painfully slow. You could make use of type inference in C# to get your anonymous type instantiated generically. Something like:
public static Func<object[], T> AnonymousInstantiator<T>(T example)
{
var ctor = typeof(T).GetConstructors().First();
var paramExpr = Expression.Parameter(typeof(object[]));
return Expression.Lambda<Func<object[], T>>
(
Expression.New
(
ctor,
ctor.GetParameters().Select
(
(x, i) => Expression.Convert
(
Expression.ArrayIndex(paramExpr, Expression.Constant(i)),
x.ParameterType
)
)
), paramExpr).Compile();
}
Now you can call,
var instantiator = AnonymousInstantiator(new { Name = default(string), Num = default(int) });
var a1 = instantiator(new object[] { "abc", 123 }); // strongly typed
var a2 = instantiator(new object[] { "xyz", 789 }); // strongly typed
// etc.
You could use the AnonymousInstantiator method to generate functions to instantiate any anonymous type with any number of properties, just that you have to pass an appropriate example first. The input parameters have to be passed as an object array. If you worry boxing performance there then you have to write a custom instantiator which accepts just string and int as input parameters, but the use of such an instantiator will be a bit more limited.
Since an anonymous type doesn't have a default empty constructor, you cannot use the Expression.New(Type) overload ... you have to provide the ConstructorInfo and parameters to the Expression.New method. To do that, you have to be able to get the Type ... so you need to make a "stub" instance of the anonymous type, and use that to get the Type, and the ConstructorInfo, and then pass the parameters to the Expression.New method.
Like this:
var exp = Expression.New(new { Name = "", Num = 0 }.GetType().GetConstructors()[0],
Expression.Constant("abc", typeof(string)),
Expression.Constant(123, typeof(int)));
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();
I have expression tree code used for data filtering, till date it was used on a Generic list List<T> and following code use to work fine:
var parameterType = Expression.Parameter(typeof(T), "obj");
var memberExpression = Expression.Property(parameterType, "Name");
It was easy to create a binary expression as follows and process the result:
var constantExpression = Expression.Constant("Jack",typeof(string));
var finalExpression = Expression.Equal(memberExpression,constantExpression);
var resultFunc = Expression.Lambda<Func<T, bool>>(finalExpression, parameterType).Compile();
// Final Result
sourceList.Where(obj => resultFunc(obj));
Here Name is a property in Type T, as result post Lambda compilation was Func<T,bool>, I use to apply the same to the Where clause of IEnumerable type. Now the underlying system has changed to use the same code on Dictionary<string,T>, so all the Type T values in the collection now have a string Key associated and type T is now accessible as a value of dictionary object. Also I am applying on a IQueryable, which takes an expression tree the final lambda post compilation at source would be Func<KeyValuePair<string,T>,bool>, therefore cannot apply the Value in the final result processing.
Following is the code modification now:
var parameterType = Expression.Parameter(typeof(KeyValuePair<string,T>), "obj");
Following code fails, since now Name property is in Value of the KeyValuePair and we cannot use it as Type T:
var memberExpression = Expression.Property(parameterType, "Name");
Any pointer to make it work or any suggestion to set me in the right direction?
You could get Expression for calling ["name"] item this way:
var nameProperty= Expression.Call(parameterType,
typeof(IDictionary<string, T>).GetMethod("get_Item"),
Expression.Constant("Name"));
or as:
var nameProperty = Expression.Property(parameterType, "Item",
new Expression[] { Expression.Constant("Name") });
Both is call of Item property
EDIT : To get Value from KeyValuePair you have to get property Key, compare it with "Name" and a property Value and compare it with value:
var parameterType = Expression.Parameter(typeof(KeyValuePair<string,T>), "obj");
var value = Expression.Property(parameterType, "Value" );
var key = Expression.Property(parameterType, "Key");
var eq1 = Expression.Equal(key, Expression.Constant("Name"));
var eq2 = Expression.Equal(value, constantExpression);
var and = Expression.And(eq1, eq2);
var lambda = Expression.Lambda(and, parameterType);
I am trying to build an expression that will call a method with an out parameter. So far I've had success, except when it comes to nullable versions of the parameters.
For this purpose lets suppose the int.TryParse(string, out int) method. I've successfully been able to build an expression (no nullables) by defining a delegate type for this purpose:
internal delegate bool TestDelegate(string input, out int value);
public static MethodInfo GetMethod()
{
return typeof(int).GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string), typeof(int).MakeByRefType() }, null);
}
public static void NormalTestExpression()
{
var method = GetMethod();
var pValue = Expression.Parameter(typeof(string), "str");
var pOutput = Expression.Parameter(typeof(int).MakeByRefType(), "value");
var call = Expression.Call(method, pValue, pOutput);
var lamd = Expression.Lambda<TestDelegate>(call, pValue, pOutput);
var func = lamd.Compile();
int output;
var result = func("3", out output);
// THIS WORKS!!!
}
I am trying to make this work with nullable types. Take for example:
internal delegate bool TestNullableDelegate(string input, out int? value);
The below will fail with an Argument Exception (GetMethod() is retrieving the correct method based off of the primitive type--same method from above)
public static void WithNullableTypeFails()
{
var method = GetMethod();
var pValue = Expression.Parameter(typeof(string), "str");
var pOutput = Expression.Parameter(typeof(int?).MakeByRefType(), "value");
value
var call = Expression.Call(method, pValue, pOutput); //Argument Exception int.TryParse() doesn't accept int? argument
var lamd = Expression.Lambda<TestNullableDelegate>(call, pValue, pOutput);
var func = lamd.Compile();
}
Expression of type 'System.Nullable`1[System.Int32]' cannot be used for parameter of type 'System.Int32' of method 'Boolean TryParse(System.String, Int32 ByRef)'
Now I am aware that this is because I am still invoking the MethodInfo which is taking the primitive int type and the delegates aren't matching. So I tried the below:
public static void WithNullableTypeAttempt()
{
var method = GetMethod();
var pValue = Expression.Parameter(typeof(string), "str");
var pOutput = Expression.Parameter(typeof(int?).MakeByRefType(), "value");
var vars = Expression.Variable(typeof(int), "tmp");
var resultvar = Expression.Variable(typeof(bool), "result");
var call = Expression.Call(method, pValue, vars);
var block = Expression.Block(
Expression.Assign(vars, Expression.Constant(default(int))),
Expression.Assign(resultvar, call),
Expression.Assign(pOutput, Expression.Convert(vars, typeof(int?))),
resultvar
);
var lamd = Expression.Lambda<TestNullableDelegate>(block, pValue, pOutput);
var func = lamd.Compile(); // Invalid Operation Exception
}
I get an invalid operation exception when I attempt to compile it:
variable 'tmp' of type 'System.Int32' referenced from scope '', but it is not defined
When I open the expression in one of the expression tree visualizers I have, I see the following:
(valueToParse, value) =>
{
var tmp = 0;
var result = int.TryParse(valueToParse, out tmp);
var value = (int?)tmp;
return result;
}
So I think I am on the right track.
How can I call this method where the types vary only by the Nullable type, keeping the delegate with the Nullable type?
You are currently using an overload of the method that does not support variables.
Quoting from the reference above:
Creates a BlockExpression that contains four expressions and has no variables.
You need to tell the block expression about the variables by using an overload that supports variables like this:
var block = Expression.Block(
new ParameterExpression[] { vars, resultvar }, //variables
Expression.Assign(vars, Expression.Constant(default(int))),
Expression.Assign(resultvar, call),
Expression.Assign(pOutput, Expression.Convert(vars, typeof(int?))),
resultvar);
I have a table with multiple columns of type DateTime. I want to generate dynamically the following Expression
filter= p => SqlFunctions.DateDiff("day", p.CreatedDate.Date, date) > 0;
when I know the name of column and the operator (the operator can be =, >=, <= and etc... .
Please, keep in mind that I want to ignore the time part form Datetime
Well, if you use SqlFunctions.DateDiff, that must mean that you're working in linq to entities. So I don't think you can use p.CreatedDate.Date, but you'll have to use EntityFunctions.TruncateTime(p.CreatedDate).
Anyway.
You could go for something like that (just the general idea, this should be of course improved).
assuming that p type is Employee
public static class ExpressionHelper {
//we create a Dictionary to manage the comparison operators,
//which will probably make things easier when calling the main method.
public static Dictionary<string, ExpressionType> Comparators = new Dictionary<string, ExpressionType>
{
{">", ExpressionType.GreaterThan},
{">=", ExpressionType.GreaterThanOrEqual},
{"<", ExpressionType.LessThan},
{"<=", ExpressionType.LessThanOrEqual}
};
public static Expression<Func<Employee, bool>> BuildFilterExpression(string datePart, DateTime date, string comparisonOperator)
{
var parameter = Expression.Parameter(typeof (Employee), "p");
Expression member = parameter;
//the property is a string here, it could be passed as parameter
//or managed another way
member = Expression.Property(member, "CreatedDate");
//let's find the dateDiffMethod
var dateDiffMethod = typeof (SqlFunctions).GetMethod("DateDiff", new[] {typeof (string), typeof (DateTime), typeof(DateTime)});
//same for TruncateTime method
var truncateTimeMethod = typeof (EntityFunctions).GetMethod("TruncateTime", new[] {typeof (DateTime)});
//first call truncateTime method (to keep only "Date" part)
var truncateExpression = Expression.Call(truncateTimeMethod, member);
//call dateDiff method on that
var dateDiffExpression = Expression.Call(dateDiffMethod, Expression.Constant(datePart), truncateExpression, Expression.Constant(date, typeof(DateTime?)));
//find the comparison operator
var comparator = Comparators[comparisonOperator];
//apply the comparison
var finalExpression = Expression.MakeBinary(comparator, dateDiffExpression, Expression.Constant(0, typeof(int?)));
return Expression.Lambda<Func<Employee, bool>>(finalExpression, new []{parameter});
}
}
usage, with your code would be something like that
filter = ExpressionHelper.BuildFilterExpression("day", date, ">")
I need an expression that gets type of every item of a collection.
I have a collection like this:
var collection = new List<object>{1,2.2,"string",'c'};
It's possible to get type of every item of collection like this:
var myVariable= collection.Select(item => item.GetType())
But I need creation of this expression at run-time.
I have to create something like myVariable dynamically, but how?!
Debugger shows me value of internal expression of myVariable like this:
{System.Linq.Enumerable+WhereSelectListIterator`2[System.Object,System.Type]}
EDIT1
Explanation of problem:
Assume that I need to select one property of an object. I cat write this query like this:
var lst = new List<MyClass>
{
new MyClass {Name = "myName1", Value = 1},
new MyClass {Name = "myName2", Value = 2}
};
var oneProperty = lst.Select(item => new {SelectedProp=item.Name});
result is a list of type anonymous contains 2 items: "myName1"&"myName2".
Now I want to add another property to resulted list that shows the type of selected property. The following code gets me thus list:
var oneProperty = lst.Select(item => new {SelectedProp=item.Name,TypeOfProp=item.GetType() });
The problem is to create such expression at run-time to give the expression to entity framework and it executes the expression. Is the problem cleared?
Given your recent edit, here's how to compile an expression such as the following at run-time:
item => new AnonymousType() { SelectProp = item.name, TypeOfProp = item.GetType() }
I've added comments to show how the expression is being constructed. You can adapt this to your needs.
[Fact]
public void CreateExpression()
{
Type argType = typeof (MyClass);
string propertyName = "Name";
ParameterExpression paramExpression = Expression.Parameter(argType, "item");
//Create "item.Name" and "item.GetType()" expressions
var propertyAccessExpression = Expression.Property(paramExpression, propertyName);
var getTypeExpression = Expression.Call(paramExpression, "GetType", Type.EmptyTypes);
Type anonType = CreateAnonymousType<String, Type>("SelectedProp", "TypeOfProp");
//"SelectProp = item.name"
MemberBinding assignment1 = Expression.Bind(anonType.GetField("SelectedProp"), propertyAccessExpression);
//"TypeOfProp = item.GetType()"
MemberBinding assignment2 = Expression.Bind(anonType.GetField("TypeOfProp"), getTypeExpression);
//"new AnonymousType()"
var creationExpression = Expression.New(anonType.GetConstructor(Type.EmptyTypes));
//"new AnonymousType() { SelectProp = item.name, TypeOfProp = item.GetType() }"
var initialization = Expression.MemberInit(creationExpression, assignment1, assignment2);
//"item => new AnonymousType() { SelectProp = item.name, TypeOfProp = item.GetType() }"
Expression expression = Expression.Lambda(initialization, paramExpression);
}
You'll need this method to create a new anonymous type:
public static Type CreateAnonymousType<TFieldA, TFieldB>(string fieldNameA, string fieldNameB)
{
AssemblyName dynamicAssemblyName = new AssemblyName("TempAssembly");
AssemblyBuilder dynamicAssembly = AssemblyBuilder.DefineDynamicAssembly(dynamicAssemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("TempAssembly");
TypeBuilder dynamicAnonymousType = dynamicModule.DefineType("AnonymousType", TypeAttributes.Public);
dynamicAnonymousType.DefineField(fieldNameA, typeof(TFieldA), FieldAttributes.Public);
dynamicAnonymousType.DefineField(fieldNameB, typeof(TFieldB), FieldAttributes.Public);
return dynamicAnonymousType.CreateType();
}
Objects like myVariable implement the generic IEnumerable<T> interface. Thus, you can retrieve the interface and get the element type as the generic parameter:
var type = myVariable.GetType();
foreach (var i in type.GetInterfaces())
{
if (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
return i.GetGenericTypeArguments()[0];
}
}
// not a generic collection
return typeof(object);
Edit: Or do you only need the types of the elements? You can achieve this with a cast to IEnumerable<object> since the type parameter of IEnumerable<T> is covariant.
collection.Cast<object>().Select(o => o.GetType())
You just need to iterate the List to get the actual Type:
var collection = new List<object> { 1, 2.2, "string", 'c' };
var myVariable = collection.Select(item => item.GetType());
foreach(var m in myVariable)
{
Console.WriteLine(m.FullName);
}
EDIT:
The Type you're seeing in the debugger:
{System.Linq.Enumerable+WhereSelectListIterator`2[System.Object,System.Type]}
is the runtime type of the Linq query represented by myVariable. You need to iterate such a query in order to get the individual values.
Cheers