设置属性,而不会在编译时知道目标类型 [英] Setting property without knowing target type at compile time

查看:80
本文介绍了设置属性,而不会在编译时知道目标类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想设置一个对象的属性值,不知道在编译时的对象类型;我想它(即不使用反射每次)要快;我知道属性名称和类型

I want to set the property value on an object without knowing the object type at compile time; I want it to be fast (i.e. not using Reflection every time); I know property name and type.

的最快方法(据我所知)是使用委托;所以这是我迄今为止:

The fastest way (afaik) is to use delegates; so this is what I have so far:

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



然后我会做这个调用:

Then I'd make this call:

User user = new User();
var userNameSetter = CreatePropertySetter(user.GetType(), "Name");
userNameSetter(user, "Bob");



但是,它不喜欢我传递用户类型的对象,而不是对象的事实,并失败以型用户的ParameterExpression不能用于System.Object的的类型的委托参数'。

However, it doesn't like the fact that I pass User type object instead of Object, and fails with "ParameterExpression of type 'User' cannot be used for delegate parameter of type 'System.Object".

我是新的表达式树,所以有点丢在这里。为什么不能把它转换用户对象? ?我需要一个地方投​​

I'm new to expression trees, so a bit lost here. Why can't it cast User to object ? Do I need a cast somewhere ?

动作并不很好看要么;会更好只返回一个代表以参数(用户用户,字符串为PropertyValue)。同样,不知道如何实现这一目标。其实,我和Delegate.CreateDelegate试过,但它会调用使用.Invoke()方法,它是缓慢的(这是唯一的方法?);同样与Expression.Lambda(非通用)。

The "Action" doesn't look great either; would be nicer to just return a delegate taking arguments (User user, string propertyValue). Again, not sure how to accomplish that. Actually, I've tried it with Delegate.CreateDelegate, but it invokes using .Invoke() method, which is slow (is this the only way?); same with Expression.Lambda (non-generic).

有什么想法?

此外,有没有一个很好的对表达式树的文档(MSDN比好)? 。MSDN版本确实缺乏细节

Also, is there a good (better than msdn) documentation on Expression Trees? The msdn version really lacks details.

推荐答案

如果你想使用表达式,则:转换 ...

If you want to use Expression, then: 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();
}



不过!你可能想看看 FastMember (也可在的NuGet),它包装的所有对你很方便的(和使用原始的IL愚蠢疯狂)。

However! You might want to look at FastMember (also available on NuGet), which wraps all of this up for you very conveniently (and uses raw IL for silly craziness).

如果你想使用一个类型的代表,你需要知道的类型提前。如果您了解的类型,你可以添加一些通用的:

If you want to use a typed delegate, you'll need to know the types in advance. If you know the types, you could add some generic:

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

这篇关于设置属性,而不会在编译时知道目标类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆