使用对象初始化器创建实例的表达式
Posted
技术标签:
【中文标题】使用对象初始化器创建实例的表达式【英文标题】:Expression to create an instance with object initializer 【发布时间】:2012-09-23 23:34:27 【问题描述】:有没有什么方法可以使用带有表达式树的对象初始化器来创建对象的实例?我的意思是创建一个表达式树来构建这个 lambda:
// my class
public class MyObject
public bool DisplayValue get; set;
// my lambda:
var lambda = (Func<bool, MyObject>)
(displayValue => new MyObject DisplayValue = displayValue );
如何使用表达式树创建这个 lambda?
更新:
我自己试了一下,写了以下代码:
public static Func<bool, dynamic> Creator;
static void BuildLambda()
var expectedType = typeof(MyObject);
var displayValueParam = Expression.Parameter(typeof(bool), "displayValue");
var ctor = Expression.New(expectedType);
var local = Expression.Parameter(expectedType, "obj");
var displayValueProperty = Expression.Property(ctor, "DisplayValue");
var returnTarget = Expression.Label(expectedType);
var returnExpression = Expression.Return(returnTarget,local, expectedType);
var returnLabel = Expression.Label(returnTarget, Expression.Default(expectedType));
var block = Expression.Block(
new[] local ,
Expression.Assign(local, ctor),
Expression.Assign(displayValueProperty, displayValueParam),
Expression.Return(Expression.Label(expectedType), local, expectedType),
returnExpression,
returnLabel
);
Creator =
Expression.Lambda<Func<bool, dynamic>>(block, displayValueParam)
.Compile();
但它会引发以下错误:
无法跳转到未定义的标签''。
大家可以帮帮我吗?
【问题讨论】:
你能阅读我的帖子:abhisheksur.com/2010/09/use-of-expression-trees-in-lamda-c.html 来生成自己吗? 感谢链接,这似乎是一篇很棒的文章。但不幸的是,我是一个新人,你的文章很重。你能发表你的建议吗? 【参考方案1】:要在表达式中表示对象初始值设定项,您应该使用Expression.MemberInit()
:
Expression<Func<bool, MyObject>> BuildLambda()
var createdType = typeof(MyObject);
var displayValueParam = Expression.Parameter(typeof(bool), "displayValue");
var ctor = Expression.New(createdType);
var displayValueProperty = createdType.GetProperty("DisplayValue");
var displayValueAssignment = Expression.Bind(
displayValueProperty, displayValueParam);
var memberInit = Expression.MemberInit(ctor, displayValueAssignment);
return
Expression.Lambda<Func<bool, MyObject>>(memberInit, displayValueParam);
要验证这是否确实符合您的要求,您可以在创建的表达式上调用 ToString()
。在这种情况下,输出如预期:
displayValue => new MyObject() DisplayValue = displayValue
【讨论】:
@svick 非常非常非常感谢你:D 我正在寻找的实际上是MemberInit
。再次感谢你。 +1 并接受
@svick 你能回答这个问题吗:***.com/questions/65434500/…【参考方案2】:
终于找到答案了:
public static Func<bool, dynamic> Creator;
static void BuildLambda()
var expectedType = typeof(MyObject);
var displayValueParam = Expression.Parameter(typeof(bool), "displayValue");
var ctor = Expression.New(expectedType);
var local = Expression.Parameter(expectedType, "obj");
var displayValueProperty = Expression.Property(local, "DisplayValue");
var returnTarget = Expression.Label(expectedType);
var returnExpression = Expression.Return(returnTarget,local, expectedType);
var returnLabel = Expression.Label(returnTarget, Expression.Default(expectedType));
var block = Expression.Block(
new[] local ,
Expression.Assign(local, ctor),
Expression.Assign(displayValueProperty, displayValueParam),
/* I forgot to remove this line:
* Expression.Return(Expression.Label(expectedType), local, expectedType),
* and now it works.
* */
returnExpression,
returnLabel
);
Creator =
Expression.Lambda<Func<bool, dynamic>>(block, displayValueParam)
.Compile();
更新:
虽然它工作正常,但@svick 在他的答案中提供了一种更好更短的方法,这正是我一直在寻找的:MemberInit
。请参阅@svick 的回答。
【讨论】:
如果您只想编译和执行代码,这会很好。但是,如果您想以其他方式使用表达式(例如在 LINQ to SQL 中),这可能效果不佳。如我的回答所示,应该使用MemberInit()
。这样,您还将获得更短、更易读的代码。
@svick 非常感谢。我想做编译和缓存函数来使用。以上是关于使用对象初始化器创建实例的表达式的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向类加载器 ClassLoader ( 类加载时机 | 隐式加载 | 显示加载 | 类加载步骤 | 装载 | 链接 | 初始化 )