C# 通过表达式的动态属性设置器不工作

C# 通过表达式的动态属性设置器不工作,c#,lambda,expression,C#,Lambda,Expression,您好,当我在控制台应用程序中运行它时,我有以下完美工作的代码,但在实际应用程序中失败,并且执行“指定的强制转换无效”。在lambda_方法(闭包、对象、对象),有人知道这是根本原因吗 public class Base { } public class Test:Base { public string TestProp { get; set; } } static void Main(string[] args)

您好,当我在控制台应用程序中运行它时,我有以下完美工作的代码,但在实际应用程序中失败,并且执行“指定的强制转换无效”。在lambda_方法(闭包、对象、对象),有人知道这是根本原因吗

    public class Base
    {

    }

    public class Test:Base
    {
        public string TestProp { get; set; }
    }

    static void Main(string[] args)
    {
        Base test = new Test();
        var prop=test.GetType().GetProperty("TestProp");
        var method = BuildSetAccessor(prop.SetMethod);
        method(test, "sa");
    }

    static Action<object, object> BuildSetAccessor(MethodInfo method)
    {

        var obj = Expression.Parameter(typeof(object), "o");
        var value = Expression.Parameter(typeof(object));

        Expression<Action<object, object>> expr =
            Expression.Lambda<Action<object, object>>(
                Expression.Call(
                    Expression.Convert(obj, method.DeclaringType),
                    method,
                    Expression.Convert(value, method.GetParameters()[0].ParameterType)),
                obj, value);


        return expr.Compile();
}
公共类基
{
}
公共类测试:基本类
{
公共字符串TestProp{get;set;}
}
静态void Main(字符串[]参数)
{
基本测试=新测试();
var prop=test.GetType().GetProperty(“TestProp”);
var方法=BuildSetAccessor(prop.SetMethod);
方法(试验,“sa”);
}
静态操作BuildSetAccessor(MethodInfo方法)
{
var obj=表达式参数(typeof(object),“o”);
var值=表达式参数(typeof(object));
表达式表达式=
Lambda(
表情,打电话(
表达式.Convert(obj,方法.DeclaringType),
方法,,
Expression.Convert(值,方法.GetParameters()[0].ParameterType)),
obj,值);
返回expr.Compile();
}

这不是目前的答案,但我建议您将代码更改为以下内容:

static Action<TOb, TPar> BuildSetAccessor<TOb, TPar>(MethodInfo method)
{
    var obj = Expression.Parameter(method.DeclaringType, "o");
    var value = Expression.Parameter(method.GetParameters()[0].ParameterType);

    if (method.GetParameters().Length > 1)
        throw new ArgumentException("Method with more than 1 parameters is not supported");

    LambdaExpression expr =
        Expression.Lambda(
            Expression.Call(
                obj,
                method,
                value),
            obj, value);

    var compiled = expr.Compile();
    return new Action<TOb, TPar>((o, p) => compiled.DynamicInvoke(o, p));
}
静态操作BuildSetAccessor(MethodInfo方法)
{
var obj=表达式参数(方法DeclaringType,“o”);
var value=Expression.Parameter(method.GetParameters()[0].ParameterType);
if(method.GetParameters().Length>1)
抛出新ArgumentException(“不支持参数超过1的方法”);
LambdaExpression表达式=
Lambda(
表情,打电话(
obj,
方法,,
价值),
obj,值);
var compiled=expr.Compile();
返回新操作((o,p)=>compiled.DynamicInvoke(o,p));
}
使用方法:

var method = BuildSetAccessor<Base, object>(prop.SetMethod);
method(test, "1");
var method=BuildSetAccessor(prop.SetMethod);
方法(试验“1”);

我认为这种方法比在LINQ查询中强制转换参数更好,因为生成的异常信息更详细。

您可以显示不起作用的类示例吗?如果您在示例中将send
int
变量发送到
TestProp
委托中,它将抛出指定的强制转换无效。然后它会失败,出现这样的异常,因为它有
string
属性,但它会得到
int
我将一个字符串传递到一个字符串字段,现在工作的示例与此非常相似,但它隐藏在代码层中,我无法公开可能在继承\属性类型\重写方面存在一些差异?因为很难判断此示例是否正常工作。这只是一种预感,但请尝试
prop.GetSetMethod()
而不是
prop.SetMethod
。谢谢,您的解决方案似乎解决了我的问题,一个问题:您为什么在新操作((o,p)=>compiled.DynamicInvoke(o,p))@迈克尔,我很乐意帮忙!我使用了非泛型的
ExpressionLambda
class。它的
Compile
方法生成
Delegate
对象,但您想要一个通用的
操作
委托,所以我将其包装。嗯,这是否意味着我可以获得赏金(据我所知,它需要额外的操作)?