I have an Expression<Func<Tin, object>>
object and I need to cast it to the Expression<Func<Tin, Tout>>
object.
In fact I have this:
x => new <>f__AnonymousType6`1(MyProp = x.MyProp)
and I need to have it as:
x => new MyType(){MyProp = x.MyProp}
Note that I have an AnonymousType
here!
To achieve this I wrote a function as below:
public static Expression<Func<Tin, Tout>> Transform<Tin, Tout>(this Expression<Func<Tin, object>> source)
{
var param = Expression.Parameter(typeof(Tout));
var body = new Visitor<Tout>(param).Visit(source.Body);
Expression<Func<Tin, Tout>> lambda = Expression.Lambda<Func<Tin, Tout>>(body, param);
return lambda;
}
And a Visitor class:
class Visitor<T> : ExpressionVisitor
{
ParameterExpression _parameter;
public Visitor(ParameterExpression parameter)=>_parameter = parameter;
protected override Expression VisitParameter(ParameterExpression node)=>_parameter;
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
throw new NotImplementedException();
var memberName = node.Member.Name;
var otherMember = typeof(T).GetProperty(memberName);
var inner = Visit(node.Expression);
return Expression.Property(inner, otherMember);
}
}
But when I run it, I get this error:
System.ArgumentException: 'Expression of type '<>f__AnonymousType6`1[System.String]' cannot be used for return type 'MyType''
Update
In Tin
and Tout
classes I have some parametric constructors and a private parameter-less constructor. I do not want to use parametric constructors as they have arguments which might be different from the expression required one. I need to build the Expression using private parameter-less constructor.
So if I use the below code:
var ctor = typeof(TOut).GetPrivateConstructor();
if (ctor != null) // can replace
return Expression.New(ctor, node.Arguments);
Or even this:
var ctor = typeof(TOut).GetPrivateConstructor();
if (ctor != null) // can replace
{
var expr = Expression.New(ctor);
expr.Update(node.Arguments);//<=====Exception in this line
return expr;
}
I will get the following error:
Incorrect number of arguments for constructor
And if I use the following:
var ctor = typeof(TOut).GetPrivateConstructor();
if (ctor != null) // can replace
return Expression.New(ctor);
I will miss the arguments!
Update 2
If I use it as:
var ctor = typeof(TOut).GetPrivateConstructor();
if (ctor != null) // can replace
{
var expr = Expression.New(ctor);
FieldInfo argementsField = expr.GetType().GetRuntimeFields().FirstOrDefault(a => a.Name == "_arguments");
argementsField.SetValue(expr, node.Arguments);
expr.Update(node.Arguments);
return expr;
}
The expression will be built, but will not be executed as it produces the following:
x => new MyType(MyProp = x.MyProp)
Which is incorrect again will produce the following error as expected:
Incorrect number of arguments for constructor