У меня есть объект Expression<Func<Tin, object>>
, и мне нужно привести его к объекту Expression<Func<Tin, Tout>>
.
На самом деле у меня есть это:
x => new <>f__AnonymousType6`1(MyProp = x.MyProp)
, и мне нужно иметь егоas:
x => new MyType(){MyProp = x.MyProp}
Обратите внимание, что у меня есть AnonymousType
здесь!
Для этого я написал следующую функцию:
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;
}
И класс Visitor:
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);
}
}
Но когда я запускаю его, я получаю эту ошибку:
System.ArgumentException: 'Выражение типа' <> f__AnonymousType6`1 [System.String] 'не может использоваться для типа возвращаемого значения 'MyType' '
Обновление
В классах Tin
и Tout
У меня есть несколько параметрических конструкторов и закрытый параметрбез конструктора.Я не хочу использовать параметрические конструкторы, поскольку они имеют аргументы, которые могут отличаться от требуемого выражения.Мне нужно построить выражение, используя закрытый конструктор без параметров.
Так что, если я использую следующий код:
var ctor = typeof(TOut).GetPrivateConstructor();
if (ctor != null) // can replace
return Expression.New(ctor, node.Arguments);
Или даже это:
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получит следующую ошибку:
Неверное количество аргументов для конструктора
И если я воспользуюсь следующим:
var ctor = typeof(TOut).GetPrivateConstructor();
if (ctor != null) // can replace
return Expression.New(ctor);
Я пропущуАргументы!
Обновление 2
Если я использую его как:
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;
}
Выражение будет построено, но не будет выполнено как оновыдает следующее:
x => new MyType(MyProp = x.MyProp)
Повторное неверное отображение приведет к следующей ошибке, как и ожидалось:
Неверное количество аргументов для конструктора