I'm creating a general setter using expression tree and here is my code
public Expression<Action<T,string>> GetAction<T>(string fieldName)
{
ParameterExpression targetExpr = Expression.Parameter(typeof(T), "Target");
MemberExpression fieldExpr = Expression.Property(targetExpr, fieldName);
ParameterExpression valueExpr = Expression.Parameter(fieldExpr.Type, "value");
UnaryExpression valueCast = (!fieldExpr.Type.IsValueType)
? Expression.TypeAs(valueExpr, fieldExpr.Type)
: Expression.Convert(valueExpr, fieldExpr.Type);
BinaryExpression assignExpr = Expression.Assign(fieldExpr, valueCast);
return Expression.Lambda<Action<T, string>>(assignExpr, targetExpr, valueExpr);
}
I don't call .Compile()
in the above method because I want to examine the expression it builds.
And my object is
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
I call the method like this
var lastname = GetAction<Person>("FirstName");
var age = GetAction<Person>("Age");
lastname.Compile()(p, "Solutions");
age.Compile()(p, "10");
The reason i pass the age as string is, i will be getting this value from XML.
It is creating Action for FirstName
without any error whereas for Age
it blows.
Error happens in this line for Age
:
return Expression.Lambda<Action<T, string>>(assignExpr, targetExpr, valueExpr);
Error:
ParameterExpression of type 'System.Int32' cannot be used for delegate parameter of type 'System.String'
Can I do something with dynamic..?
I'm hoping someone will have some solution. Thanks
You should call Convert.ChangeType
for type conversion:
public static Expression<Action<T, string>> GetAction<T>(string fieldName)
{
ParameterExpression targetExpr = Expression.Parameter(typeof(T), "Target");
MemberExpression fieldExpr = Expression.Property(targetExpr, fieldName);
ParameterExpression valueExpr = Expression.Parameter(typeof(string), "value");
MethodCallExpression convertExpr = Expression.Call(typeof(Convert),
"ChangeType", null, valueExpr, Expression.Constant(fieldExpr.Type));
UnaryExpression valueCast = Expression.Convert(convertExpr, fieldExpr.Type);
BinaryExpression assignExpr = Expression.Assign(fieldExpr, valueCast);
return Expression.Lambda<Action<T, string>>(assignExpr, targetExpr, valueExpr);
}
The problem is the following:
You are returning an Expression<Action<T,string>>
, which basically means that the result will be a string
. On the other hand, you are passing in "Age" as the name of the field the action should return. Age
however is of type int
, not string
.
You can solve this in at least two ways:
GetAction
method that specifies the return type. ToString
on the returned property to the expression.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.