将字符串解析为C#lambda Func

有没有办法将lambda的字符串表示转换为lambda Func?

Func func = Parse("product => product.Name.Length > 0"); 

我尝试了动态LINQ但它没有按预期工作 – 例如它不期望lambda语法=>。

答案摘要:

  • 编写我自己的C#编译器 – 非常有趣
  • 启动外部编译器(如csc.exe) – 非常慢
  • 使用DLINQ – 正如我所说,我不知道它如何解析lambda表达式

为什么我需要这个:因为没有办法将lambdas传递给自定义属性,比如

 [Secure(role => role.CanDoThis && role.AllowedCount > 5)] 

因此,作为一种解决方法,我想将lambda作为字符串传递:“role => role.CanDoThis && role.AllowedCount> 5”。 但似乎我必须像这样使用DLINQ:“CanDoThis && AllowedCount> 5” – 因为这是它理解的语法。 但我的问题是关于真正的lambdas,我在询问时已经使用过DLINQ了。

它们是许多可用的lambda表达式解析器。 其中一些是Lambda-Parser , Sprache

示例代码:

例1:字符串concat和数字计算:

 string code = "2.ToString()+(4*2)"; // C# code Func func = ExpressionParser.Compile>(code); // compile code string result = func(); // result = "28" 

您可以解析字符串并使用Expression类构建lambda表达式,基本上复制了编译器的function。

我想你必须求助于CSharpCodeProvider。 但是,处理所有可能的局部变量引用可能并不简单。 您如何告诉CSharpCodeProvider有关lambda参数的类型? 我可能会创建一个如下所示的模板类:

 class ExpressionContainer { public Expression> TheExpression; public string Length; public ExpressionContainer() { TheExpression = ; } } 

然后做这样的事情:

 string source = ; Assembly a; using (CSharpCodeProvider provider = new CSharpCodeProvider(...) { List assemblies = new List(); foreach (Assembly x in AppDomain.CurrentDomain.GetAssemblies()) { try { assemblies.Add(x.Location); } catch (NotSupportedException) { // Dynamic assemblies will throw, and in .net 3.5 there seems to be no way of finding out whether the assembly is dynamic before trying. } } CompilerResults r = provider.CompileAssemblyFromSource(new CompilerParameters(assemblies.ToArray()) { GenerateExecutable = false, GenerateInMemory = true }, source); if (r.Errors.HasErrors) throw new Exception("Errors compiling expression: " + string.Join(Environment.NewLine, r.Errors.OfType().Select(e => e.ErrorText).ToArray())); a = r.CompiledAssembly; } object o = a.CreateInstance("ExpressionContainer"); var result = ( Expression>)o.GetType().GetProperty("TheExpression").GetValue(o); 

但请注意,对于长时间运行的应用程序,您应该在单独的应用程序域中创建所有这些内存中程序集,因为在卸载它们所在的应用程序域之前无法释放它们。

您可以使用CSharpCodeProvider执行某些操作 (使用更多代码包装表达式以创建有效类并将其编译为程序集,然后加载程序集)。

我相信LINQPad就是这样做的。

回答你更具体的问题,(你可能已经知道了,但无论如何我会尝试提及它),你可以创建一个字典,将可以是常量(整数或枚举)的值映射到lambdas。

 sealed class Product { public bool CanDoThis { get; set; } public int AllowedCount { get; set; } } public enum SecureFuncType { Type1, Type2, Type3 } sealed class SecureAttribute : Attribute { [NotNull] readonly Func mFunc; public SecureAttribute(SecureFuncType pType) { var secureFuncs = new Dictionary> { { SecureFuncType.Type1, role => role.CanDoThis && role.AllowedCount > 1 }, { SecureFuncType.Type2, role => role.CanDoThis && role.AllowedCount > 2 }, { SecureFuncType.Type3, role => role.CanDoThis && role.AllowedCount > 3 } }; mFunc = secureFuncs[pType]; } } 

 [Secure(SecureFuncType.Type1)] sealed class TestClass { } // etc...