ParameterExpression de tipo 'System.Int32' no puede usarse para un parámetro delegado de tipo 'System.String'

c# delegates dynamic expression-trees generics

Pregunta

Estoy creando un setter general usando el árbol de expresiones y aquí está mi código

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);
}

No llamo a .Compile() en el método anterior porque quiero examinar la expresión que genera.

Y mi objeto es

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }

}

Llamo al metodo asi

var lastname = GetAction<Person>("FirstName");
var age = GetAction<Person>("Age");

lastname.Compile()(p, "Solutions");
age.Compile()(p, "10");

La razón por la que paso la edad como cadena es que obtendré este valor de XML.

Está creando Acción para el FirstName sin ningún error, mientras que para Age sopla.

El error ocurre en esta línea para la Age :

 return Expression.Lambda<Action<T, string>>(assignExpr, targetExpr, valueExpr);

Error:

ParameterExpression de tipo 'System.Int32' no puede usarse para un parámetro delegado de tipo 'System.String'

¿Puedo hacer algo con dinámica ..?

Espero que alguien tenga alguna solución. Gracias

Respuesta aceptada

Debería llamar a Convert.ChangeType para la conversión de tipos:

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);
}

Respuesta popular

El problema es el siguiente:

Está devolviendo una Expression<Action<T,string>> , que básicamente significa que el resultado será una string . Por otro lado, está pasando "Edad" como el nombre del campo que debe devolver la acción. Sin embargo, la Age es de tipo int , no de string .

Puedes resolver esto al menos de dos maneras:

  1. Agregue un segundo parámetro genérico a su método GetAction que especifique el tipo de retorno.
  2. Agregue una llamada a ToString en la propiedad devuelta a la expresión.


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow