我有一个方法根据传递给它的动作委托来改变“帐户”对象:
public static void AlterAccount(string AccountID, Action<Account> AccountAction) {
Account someAccount = accountRepository.GetAccount(AccountID);
AccountAction.Invoke(someAccount);
someAccount.Save();
}
这可以按预期工作......
AlterAccount("Account1234", a => a.Enabled = false);
...但是现在我想尝试做的是这样的方法:
public static void AlterAccount(string AccountID, string AccountActionText) {
Account someAccount = accountRepository.GetAccount(AccountID);
Action<Account> AccountAction = MagicLibrary.ConvertMagically<Action<Account>>(AccountActionText);
AccountAction.Invoke(someAccount);
someAccount.Save();
}
然后可以像:
一样使用它AlterAccount("Account1234", "a => a.Enabled = false");
禁用帐户“Account1234”。
我已经看过linq dynamic query library了,它似乎或多或少地做了我想要的但是对于Func类型的委托,而且我对表达式树等的了解并不足以弄清楚如何实现我想要的。
有没有一种简单的方法可以做我想要的,或者我是否需要正确学习表达式并编写大量代码?
(我想这样做的原因是允许从powershell脚本中批量更新帐户对象的简单方法,其中用户可以指定lambda表达式来执行更改。)
答案 0 :(得分:4)
动态LINQ库是一个很好的选择,因为它会生成表达式,您可以轻松地编译成代码。
您提供的示例实际上会生成一个布尔值 - 因此您应该能够请求Func并且可能会对其进行排序。
编辑:这当然是错误的,因为表达式根本没有赋值。
所以,另一个可能的方法是采取两个lambdas。一个找到你想要的属性,一个提供一个值:
(a =&gt; a.AccountId),(a =&gt; true)
然后使用reflection将第一个lambda中引用的属性设置为第二个lambda的结果。 Hackish,但与调用C#编译器相比,它仍然可能是轻量级的。
这样你就不必自己做很多代码 - 你得到的表达式将包含你需要的大部分内容。
答案 1 :(得分:3)
您可以尝试:Dynamic Lambda Expressions Using An Isolated AppDomain
它使用CodeDOM编译器编译lambda表达式。为了处理创建的内存中程序集,编译器在隔离的AppDomain
上运行。对于通过域边界传递表达式,必须将其序列化。唉,Expression<>
不是Serializable
。所以,必须使用一个技巧。所有细节都在帖子中解释。
顺便说一句,我是该组件的作者。我非常希望听到你的反馈意见。
答案 2 :(得分:1)
没有通用的方法可以在没有完整编译的情况下将字符串解析为lambda表达式,因为lambda表达式可以引用在lambda表达式之外定义的内容。我知道没有库可以处理你想要的特定情况。在C#讨论组的thread上对此进行了长时间的讨论。
获得所需内容的最简单方法是在运行时编译方法。你可以编写一个函数,它接受字符串“a.Enabled = true; return a;”并将其置于以Account作为参数的函数中间。我会使用此library作为起点,但您也可以使用another thread中提到的函数。
答案 3 :(得分:0)
这很简单:
基本上,您需要使用CodeDom构建以下类:
using System;
using MyNamespace1;
using ...
using MyNamespace[N];
namespace MyNamespace.GeneratedTypes
{
public class ExpressionContainer[M] : IHasAccountAction
{
public Action<Account> AccountAction {
get {
return [CodeSnippedExpression must be used here];
}
}
}
}
假设IHasAccountAction
是:
public IHasAccountAction {
public Action<Account> AccountAction { get; }
}
如果这样做,您可以轻松地从字符串中获取编译的表达式。如果您需要其表达式树表示,请在生成的类型中使用Expression<Action<Account>>
而不是Action<Account>
。