C# 在编译时不知道目标类型的情况下设置属性

C# 在编译时不知道目标类型的情况下设置属性,c#,c#-4.0,C#,C# 4.0,我想在编译时在不知道对象类型的情况下设置对象的属性值;我希望它是快速的(即不是每次都使用反射);我知道物业的名称和类型 最快的方法(afaik)是使用代理;这就是我到目前为止所做的: class User // this is an example.. Assume I don't know which type this is. { public string Name {get;set;} } public static Action<object, object&

我想在编译时在不知道对象类型的情况下设置对象的属性值;我希望它是快速的(即不是每次都使用反射);我知道物业的名称和类型

最快的方法(afaik)是使用代理;这就是我到目前为止所做的:

class User // this is an example.. Assume I don't know which type this is.
 {
    public string Name {get;set;}   
 }

public static Action<object, object> CreatePropertySetter(Type targetType, string propertyName)
{
    ParameterExpression targetObjParamExpr = Expression.Parameter(targetType);
    ParameterExpression valueParamExpr = Expression.Parameter(targetType.GetProperty(propertyName).PropertyType);

    MemberExpression propertyExpr = Expression.Property(targetObjParamExpr, propertyName);

    BinaryExpression assignExpr = Expression.Assign(targetObjParamExpr, valueParamExpr);

    Action<object, object> result = Expression.Lambda<Action<object, object>>(assignExpr, targetObjParamExpr, valueParamExpr).Compile();
    return result;
}
但是,它不喜欢这样一个事实,即我传递的是用户类型object而不是object,并且由于“ParameterExpression类型'User'不能用于'System.object'类型的委托参数”而失败

我不熟悉表达式树,所以在这里有点迷茫。为什么它不能将用户强制转换为对象?我需要找个演员吗

“行动”看起来也不太好;最好只返回一个带参数的委托(User,string propertyValue)。同样,我也不知道如何做到这一点。实际上,我已经尝试过Delegate.CreateDelegate,但是它使用.Invoke()方法调用,这很慢(这是唯一的方法吗?);与表达式.Lambda相同(非泛型)

有什么想法吗


另外,是否有关于表达式树的良好(优于msdn)文档?msdn版本确实缺少详细信息。

如果要使用表达式,则:
Convert

static void Main()
{
    var setter = CreatePropertySetter(typeof (User), "Name");
    var obj = new User();
    setter(obj, "Fred");
}
public static Action<object, object> CreatePropertySetter(Type targetType, string propertyName)
{
    var target = Expression.Parameter(typeof (object), "obj");
    var value = Expression.Parameter(typeof (object), "value");
    var property = targetType.GetProperty(propertyName);
    var body = Expression.Assign(
        Expression.Property(Expression.Convert(target, property.DeclaringType), property),
        Expression.Convert(value, property.PropertyType));

    var lambda = Expression.Lambda<Action<object, object>>(body, target, value);
    return lambda.Compile();
}
static void Main()
{
var setter=CreatePropertySetter(typeof(User),“Name”);
var obj=新用户();
塞特(obj,“弗雷德”);
}
公共静态操作CreatePropertySetter(类型targetType,字符串propertyName)
{
var target=表达式参数(typeof(object),“obj”);
var value=表达式参数(typeof(object),“value”);
var property=targetType.GetProperty(propertyName);
var body=Expression.Assign(
Expression.Property(Expression.Convert(target,Property.DeclaringType),Property),
Convert(value,property.PropertyType));
var lambda=Expression.lambda(也可在NuGet上获得),它为您非常方便地包装了所有这些内容(并使用原始IL进行愚蠢的疯狂)

如果要使用类型化委托,则需要事先了解类型。如果知道类型,则可以添加一些泛型:

static void Main()
{
    var setter = CreatePropertySetter<User,string>("Name");
    var obj = new User();
    setter(obj, "Fred");
}
public static Action<TType, TValue> CreatePropertySetter<TType, TValue>(string propertyName)
{
    var target = Expression.Parameter(typeof (TType), "obj");
    var value = Expression.Parameter(typeof (TValue), "value");
    var property = typeof(TType).GetProperty(propertyName);
    var body = Expression.Assign(
        Expression.Property(target, property),
        value);

    var lambda = Expression.Lambda<Action<TType, TValue>>(body, target, value);
    return lambda.Compile();
}
static void Main()
{
var setter=CreatePropertySetter(“名称”);
var obj=新用户();
塞特(obj,“弗雷德”);
}
公共静态操作CreatePropertySetter(字符串propertyName)
{
var target=Expression.Parameter(typeof(TType),“obj”);
var值=表达式参数(typeof(TValue),“value”);
var property=typeof(TType).GetProperty(propertyName);
var body=Expression.Assign(
表达式。属性(目标、属性),
价值);
var lambda=Expression.lambda(主体、目标、值);
返回lambda.Compile();
}

太长了,读不下去了。写下清晰的简洁的问题,并用相关的信息和细节来编辑。虽然这是整个问题的摘要,而且有足够的细节来提供答案,IMO。这有点偏离了方向,但是你觉得自己是一个习惯于使用模板的C++程序员,但现在不能在C语言中使用。在C++中这是微不足道的。这可能是你正在寻找的是“代码>用户<代码>一个值类型或引用类型?这是很棒的!)谢谢!我有很多和你的第二个例子一样的东西,但是我正在努力使它更通用。我想我看到了我做错了什么。谢谢你在FASTFART上的提示。首先看一看。太棒了,我一整天都在寻找类似的东西。我能找到的只是带有打字代表的物品!谢谢!
static void Main()
{
    var setter = CreatePropertySetter<User,string>("Name");
    var obj = new User();
    setter(obj, "Fred");
}
public static Action<TType, TValue> CreatePropertySetter<TType, TValue>(string propertyName)
{
    var target = Expression.Parameter(typeof (TType), "obj");
    var value = Expression.Parameter(typeof (TValue), "value");
    var property = typeof(TType).GetProperty(propertyName);
    var body = Expression.Assign(
        Expression.Property(target, property),
        value);

    var lambda = Expression.Lambda<Action<TType, TValue>>(body, target, value);
    return lambda.Compile();
}