C# 表达式树属性设置程序InvalidCastException

C# 表达式树属性设置程序InvalidCastException,c#,lambda,expression,C#,Lambda,Expression,我在设计时在代码中定义一组映射,然后在执行一些数据提取后在运行时执行这些映射: public class FormExtractionMap<T> { public Expression<Func<T>> Destination { get; set; } public string Source { get; set; } } 然后我使用表达式扩展来创建setter、编译和执行属性赋值 public static TEntity

我在设计时在代码中定义一组映射,然后在执行一些数据提取后在运行时执行这些映射:

public class FormExtractionMap<T>
{
    public Expression<Func<T>> Destination { get; set; }

    public string Source { get; set; }

}
然后我使用表达式扩展来创建setter、编译和执行属性赋值

    public static TEntity Set<TEntity, TProperty>(
        this TEntity obj,
        Expression<Func<TEntity, TProperty>> selector,
        TProperty value)
    {
        var setterExpr = CreateSetter(selector);
        setterExpr.Compile()(obj, value);
        return obj;
    }

    private static Expression<Action<TEntity, TProperty>> CreateSetter<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> selector)
    {
        ParameterExpression valueParameterExpression = Expression.Parameter(typeof(TProperty), "value");
        Expression targetExpression = selector.Body is UnaryExpression ? ((UnaryExpression)selector.Body).Operand : selector.Body;
        var newValue = Expression.Parameter(selector.Body.Type);

        return Expression.Lambda<Action<TEntity, TProperty>>
        (
            Expression.Assign(targetExpression, Expression.Convert(valueParameterExpression, targetExpression.Type)),
            selector.Parameters.Single(),
            valueParameterExpression
        );
    }
公共静态张力集(
这是一个潜在的目标,
表达式选择器,
t属性值)
{
var setterExpr=CreateSetter(选择器);
seterexpr.Compile()(对象,值);
返回obj;
}
专用静态表达式CreateSetter(表达式选择器)
{
ParameterExpression值ParameterExpression=Expression.Parameter(typeof(TProperty),“value”);
表达式targetExpression=selector.Body是UnaryExpression?((UnaryExpression)selector.Body)。操作数:selector.Body;
var newValue=Expression.Parameter(selector.Body.Type);
返回表达式.Lambda
(
Expression.Assign(targetExpression,Expression.Convert(valueParameterExpression,targetExpression.Type)),
selector.Parameters.Single(),
valueParameterExpression
);
}
如果源是一个字符串,而目标是一个字符串,则可以很好地分配值。如果目标是setterExpr.Compile()上的双精度(obj,value)我得到:

System.InvalidCastException:无法强制转换类型为的对象 “System.String”以键入“System.Double”


我认为“Expression.Convert”正在处理类型转换,但显然不是。请问我做错了什么?

所以,我最终解决了这个问题。Convert类似于显式转换(Foo)条,而不是“Convert”所暗示的那样。我的结局是:

private static Expression<Action<TEntity, TProperty>> CreateSetter<TEntity, TProperty>(
            Expression<Func<TEntity, TProperty>> selector, Type valueParameterType)
        {
            ParameterExpression valueParameterExpression = Expression.Parameter(typeof(object), "value");
            Expression targetExpression = selector.Body is UnaryExpression ? ((UnaryExpression)selector.Body).Operand : selector.Body;
            
            var resultBody = ConvertToDestination(valueParameterExpression, valueParameterType, targetExpression);
            
            return Expression.Lambda<Action<TEntity, TProperty>>
            (
                Expression.Assign(targetExpression, resultBody),
                selector.Parameters.Single(),
                valueParameterExpression
            );

        }

        private static Expression ConvertToDestination(ParameterExpression valueParameterExpression, Type valueParameterType, Expression targetExpression)
        {
            if (valueParameterType == typeof(string))
            {
                switch (targetExpression.Type)
                {
                    case Type _ when targetExpression.Type == typeof(double):
                        return Expression.Call(typeof(Convert), "ToDouble", null, valueParameterExpression);

                    case Type _ when targetExpression.Type == typeof(int):
                        return Expression.Call(typeof(Convert), "ToInt", null, valueParameterExpression);

                    default:
                        return Expression.Convert(valueParameterExpression, targetExpression.Type);
                }
            }

            return Expression.Convert(valueParameterExpression, targetExpression.Type);
        }
私有静态表达式CreateSetter(
表达式选择器,类型值ParameterType)
{
ParameterExpression值ParameterExpression=Expression.Parameter(typeof(object),“value”);
表达式targetExpression=selector.Body是UnaryExpression?((UnaryExpression)selector.Body)。操作数:selector.Body;
var resultBody=ConvertToDestination(valueParameterExpression、valueParameterType、targetExpression);
返回表达式.Lambda
(
Expression.Assign(targetExpression,resultBody),
selector.Parameters.Single(),
valueParameterExpression
);
}
专用静态表达式ConvertToDestination(ParameterExpression值ParameterExpression,类型值ParameterType,表达式targetExpression)
{
if(valueParameterType==类型(字符串))
{
开关(targetExpression.Type)
{
当targetExpression.Type==typeof(double)时的大小写类型uu:
返回表达式.Call(typeof(Convert),“ToDouble”,null,valueParameterExpression);
当targetExpression.Type==typeof(int)时,大小写类型为:
返回表达式.Call(typeof(Convert),“ToInt”,null,valueParameterExpression);
违约:
返回表达式.Convert(valueParameterExpression,targetExpression.Type);
}
}
返回表达式.Convert(valueParameterExpression,targetExpression.Type);
}

然而,我认为这是混乱的,冗长的,坦率地说没有必要的,因为我能够在几个小时内使用AutoMapper实现类似的功能。Automapper在类型转换、缓存地图等方面做得更好。因此,真正的解决方案是重新考虑因素,而不是重新发明轮子。

因此,我最终解决了这个问题。Convert类似于显式转换(Foo)条,而不是“Convert”所暗示的那样。我的结局是:

private static Expression<Action<TEntity, TProperty>> CreateSetter<TEntity, TProperty>(
            Expression<Func<TEntity, TProperty>> selector, Type valueParameterType)
        {
            ParameterExpression valueParameterExpression = Expression.Parameter(typeof(object), "value");
            Expression targetExpression = selector.Body is UnaryExpression ? ((UnaryExpression)selector.Body).Operand : selector.Body;
            
            var resultBody = ConvertToDestination(valueParameterExpression, valueParameterType, targetExpression);
            
            return Expression.Lambda<Action<TEntity, TProperty>>
            (
                Expression.Assign(targetExpression, resultBody),
                selector.Parameters.Single(),
                valueParameterExpression
            );

        }

        private static Expression ConvertToDestination(ParameterExpression valueParameterExpression, Type valueParameterType, Expression targetExpression)
        {
            if (valueParameterType == typeof(string))
            {
                switch (targetExpression.Type)
                {
                    case Type _ when targetExpression.Type == typeof(double):
                        return Expression.Call(typeof(Convert), "ToDouble", null, valueParameterExpression);

                    case Type _ when targetExpression.Type == typeof(int):
                        return Expression.Call(typeof(Convert), "ToInt", null, valueParameterExpression);

                    default:
                        return Expression.Convert(valueParameterExpression, targetExpression.Type);
                }
            }

            return Expression.Convert(valueParameterExpression, targetExpression.Type);
        }
私有静态表达式CreateSetter(
表达式选择器,类型值ParameterType)
{
ParameterExpression值ParameterExpression=Expression.Parameter(typeof(object),“value”);
表达式targetExpression=selector.Body是UnaryExpression?((UnaryExpression)selector.Body)。操作数:selector.Body;
var resultBody=ConvertToDestination(valueParameterExpression、valueParameterType、targetExpression);
返回表达式.Lambda
(
Expression.Assign(targetExpression,resultBody),
selector.Parameters.Single(),
valueParameterExpression
);
}
专用静态表达式ConvertToDestination(ParameterExpression值ParameterExpression,类型值ParameterType,表达式targetExpression)
{
if(valueParameterType==类型(字符串))
{
开关(targetExpression.Type)
{
当targetExpression.Type==typeof(double)时的大小写类型uu:
返回表达式.Call(typeof(Convert),“ToDouble”,null,valueParameterExpression);
当targetExpression.Type==typeof(int)时,大小写类型为:
返回表达式.Call(typeof(Convert),“ToInt”,null,valueParameterExpression);
违约:
返回表达式.Convert(valueParameterExpression,targetExpression.Type);
}
}
返回表达式.Convert(valueParameterExpression,targetExpression.Type);
}

然而,我认为这是混乱的,冗长的,坦率地说没有必要的,因为我能够在几个小时内使用AutoMapper实现类似的功能。Automapper在类型转换、缓存映射等方面做得更好。因此,真正的解决方案是重新考虑因素,而不是重新发明轮子。

如果您在代码中以注释的形式编写所需的表达式,将有助于可视化您试图构建的内容。targetExpression可以是任何类型,valueParameterExpression可能是任何类型,但只能是那些可以转换的类型
private static Expression<Action<TEntity, TProperty>> CreateSetter<TEntity, TProperty>(
            Expression<Func<TEntity, TProperty>> selector, Type valueParameterType)
        {
            ParameterExpression valueParameterExpression = Expression.Parameter(typeof(object), "value");
            Expression targetExpression = selector.Body is UnaryExpression ? ((UnaryExpression)selector.Body).Operand : selector.Body;
            
            var resultBody = ConvertToDestination(valueParameterExpression, valueParameterType, targetExpression);
            
            return Expression.Lambda<Action<TEntity, TProperty>>
            (
                Expression.Assign(targetExpression, resultBody),
                selector.Parameters.Single(),
                valueParameterExpression
            );

        }

        private static Expression ConvertToDestination(ParameterExpression valueParameterExpression, Type valueParameterType, Expression targetExpression)
        {
            if (valueParameterType == typeof(string))
            {
                switch (targetExpression.Type)
                {
                    case Type _ when targetExpression.Type == typeof(double):
                        return Expression.Call(typeof(Convert), "ToDouble", null, valueParameterExpression);

                    case Type _ when targetExpression.Type == typeof(int):
                        return Expression.Call(typeof(Convert), "ToInt", null, valueParameterExpression);

                    default:
                        return Expression.Convert(valueParameterExpression, targetExpression.Type);
                }
            }

            return Expression.Convert(valueParameterExpression, targetExpression.Type);
        }