从函数表达式创建 lambda 操作
创建一个 lambda 函数相对容易,该函数将返回对象的属性值,甚至包括深层属性...
Func<Category, string> getCategoryName = new Func<Category, string>(c => c.Name);
并且可以按如下方式调用...
string categoryName = getCategoryName(this.category);
但是,仅给定 上面的结果函数(或最初用于创建函数的表达式),任何人都可以提供一种简单的方法来创建相反的操作...
Action
...这将允许按如下方式设置相同的属性值?
setCategoryName(this.category, "");
请注意,我正在寻找一种从函数或表达式以编程方式创建操作的方法 - 我希望我已经表明我已经知道如何手动创建它。
我愿意接受在 .net 3.5 和 4.0 中都有效的答案。
谢谢。
更新:
也许我的问题不清楚,所以让我尝试更清楚地展示我想要做什么。
我有以下方法(我为了这个问题而创建的)...
void DoLambdaStuff<TObject, TValue>(TObject obj, Expression<Func<TObject, TValue>> expression) {
Func<TObject, TValue> getValue = expression.Compile();
TValue stuff = getValue(obj);
Expression<Action<TObject, TValue>> assignmentExpression = (o, v) => Expression<TObject>.Assign(expression, Expression.Constant(v, typeof(TValue)));
Action<TObject, TValue> setValue = assignmentExpression.Compile();
setValue(obj, stuff);
}
我正在寻找的是如何在代码中创建“赋值表达式”,以便我可以将其编译为 setValue?我认为它与 Expression.Assign 有关,但我根本无法计算出完成代码的正确参数组合。
最终结果是能够调用
Category category = *<get object from somewhere>*;
this.DoLambdaStuff(category, c => c.Name);
,这反过来将为 Category 对象的“Name”属性创建一个 getter 和一个 setter。
上面的版本可以编译,但是当我调用 setValue() 时,它会导致 ArgumentException 并显示“表达式必须可写”。
再次感谢。
It is relatively easy to create a lambda function that will return the value of a property from an object, even including deep properties...
Func<Category, string> getCategoryName = new Func<Category, string>(c => c.Name);
and this can be called as follows...
string categoryName = getCategoryName(this.category);
But, given only the resulting function above (or the expression originally used to create the function), can anybody provide an easy way to create the opposing action...
Action<Category, string> setCategoryName = new Action<Category, string>((c, s) => c.Name = s);
...that will enable the same property value to be set as follows?
setCategoryName(this.category, "");
Note that I am looking for a way to create the action programatically from the function or expression - I hope that I have shown that I already know how to create it manually.
I am open to answers that work in both .net 3.5 and 4.0.
Thanks.
UPDATE:
Perhaps I am not being clear in my question, so let me try and demonstrate more clearly what I am trying to do.
I have the following method (that I have created for the purposes of this question)...
void DoLambdaStuff<TObject, TValue>(TObject obj, Expression<Func<TObject, TValue>> expression) {
Func<TObject, TValue> getValue = expression.Compile();
TValue stuff = getValue(obj);
Expression<Action<TObject, TValue>> assignmentExpression = (o, v) => Expression<TObject>.Assign(expression, Expression.Constant(v, typeof(TValue)));
Action<TObject, TValue> setValue = assignmentExpression.Compile();
setValue(obj, stuff);
}
What I am looking for is how do I create the "assignmentExpression" within the code so that I can compile it into setValue? I figure it is related to Expression.Assign, but I simply cannot work out the correct combination of parameters to complete the code.
The eventual result is to be able to call
Category category = *<get object from somewhere>*;
this.DoLambdaStuff(category, c => c.Name);
and this in turn will create a getter and a setter for the "Name" property of the Category object.
The version above compiles, but when I call setValue() it results in an ArgumentException with "Expression must be writeable".
Thanks again.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
好吧,我正在寻找的代码是这样的......
这段代码有效,但仅适用于浅层属性(即直接对象的属性),但不适用于深层属性 - 尽管 getter 函数可以适用于深层属性特性。知道是否有人可以帮助我修改它以处理深层属性会很有趣,但我会将其作为一个单独的问题提出。
Ok, the code I am looking for goes something like this...
This code works, but only for shallow properties (that is, properties of the immediate object) but does not work for deep properties - although the getter function can work for deep properties. It would be interesting to know if anybody can help me modify this to work with deep properties but I will raise this as a seperate question.
正如马丁上面指出的,“深层”属性打破了他的解决方案。它不起作用的原因是这个表达式:
其原因并不是立即显而易见的:派生类声明了自己的属性 getter,它重定向到基类,但没有定义相应的 setter。
为了解决这个问题,您需要通过反射来定位属性,查找其声明类型,然后从声明者中获取相应的属性。与派生类中获得的属性不同,声明者中的属性具有 getter 和 setter,因此是可赋值的。 (这假设属性的 setter 已被声明:如果声明者不提供 setter,那么其他人不可能提供它。)
这是解决此问题的骨架实现。将上面对
Expression.Property
的调用替换为下面对GetPropertyOrField
的调用,Martin 的解决方案将会起作用。As Martin noted above, "deep" properties break his solution. The reason why it does not work is this expression:
The reason for it is not immediately obvious: the derived class declares its own property getter, which redirects to the base class, but does not define a corresponding setter.
In order to work around this issue, you need to locate the property through reflection, look for its declaring type, and then get the corresponding property from the declarer. Unlike the property you get on the derived class, the property from the declarer has a getter and a setter, and is therefore assignable. (This assumes that a setter of the property is declared at all: if the declarer does not provide a setter, then nobody else could possibly provide it.)
Here is a skeletal implementation that addresses this problem. Replace the above call to
Expression.Property
with the call ofGetPropertyOrField
below, and Martin's solution is going to work.这应该可以使用 表达式树 实现,它可以从 lambda 创建表达式,修改,然后编译成委托。
This should be possible using expression trees, which can be created from lambda expressions, modified, and then compiled into a delegate.