在编译时设置属性而不知道目标类型

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

最快的方式(afaik)是使用代表; 所以这就是我到目前为止:

class User // this is an example.. Assume I don't know which type this is. { public string Name {get;set;} } public static Action 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 result = Expression.Lambda<Action>(assignExpr, targetObjParamExpr, valueParamExpr).Compile(); return result; } 

然后我打电话:

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

但是,它不喜欢我传递User类型对象而不是Object的事实,并且失败并且“ UserExpression类型’User’不能用于’System.Object’类型的委托参数

我是表达树木的新手,所以有点迷失在这里。 为什么不能将User转换为对象? 我需要某个演员吗?

“行动”也看起来不太好; 会更好地返回一个带参数的委托(用户用户,字符串propertyValue)。 再次,不知道如何实现这一目标。 实际上,我已经使用Delegate.CreateDelegate尝试了它,但它使用.Invoke()方法调用,这很慢(这是唯一的方法吗?); 与Expression.Lambda(非generics)相同。

有什么想法吗 ?

另外,表达树上有一个好的(比msdn更好的)文档吗? msdn版本确实缺乏细节。

如果你想使用Expression,那么: Convert ……

 static void Main() { var setter = CreatePropertySetter(typeof (User), "Name"); var obj = new User(); setter(obj, "Fred"); } public static Action 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>(body, target, value); return lambda.Compile(); } 

然而! 你可能想看一下FastMember (也可以在NuGet上找到),它可以非常方便地为你完成所有这些工作(并使用原始的IL来实现愚蠢的疯狂)。

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

 static void Main() { var setter = CreatePropertySetter("Name"); var obj = new User(); setter(obj, "Fred"); } public static Action CreatePropertySetter(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>(body, target, value); return lambda.Compile(); }