将字符串解析为 C# lambda Func
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1707854/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Parse string to C# lambda Func
提问by queen3
Is there a way to convert string representation of lambda to a lambda Func?
有没有办法将 lambda 的字符串表示形式转换为 lambda Func?
Func<Product, bool> func = Parse<Product, bool>("product => product.Name.Length > 0");
I tried Dynamic LINQ but it doesn't work as expected - for example it doesn't expect lambda syntax =>.
我尝试了动态 LINQ,但它没有按预期工作 - 例如它不期望 lambda 语法 =>。
Summary of answers:
答案摘要:
- writing my own C# compiler - very funny
- firing up external compiler (like csc.exe) - very slow
- using DLINQ - as I said I don't see how it can parse lambdaexpressions
- 编写我自己的 C# 编译器 - 非常有趣
- 启动外部编译器(如 csc.exe) - 非常慢
- 使用 DLINQ - 正如我所说,我不知道它如何解析lambda表达式
Why do I need this: because there's no way to pass lambdas to custom attributes like
为什么我需要这个:因为没有办法将 lambdas 传递给自定义属性,例如
[Secure(role => role.CanDoThis && role.AllowedCount > 5)]
So as a workaround I'd like to pass lambda as string: "role => role.CanDoThis && role.AllowedCount > 5". But seems like I'll have to use DLINQ like this: "CanDoThis && AllowedCount > 5" - since that's the syntax it understands. But my question was about true lambdas, I've already used DLINQ at the time of asking.
因此,作为一种解决方法,我想将 lambda 作为字符串传递:“role => role.CanDoThis && role.AllowedCount > 5”。但似乎我必须像这样使用 LINQ:“CanDoThis && AllowedCount > 5”——因为这是它理解的语法。但我的问题是关于真正的 lambdas,我在提问时已经使用过 LINQ。
回答by tvanfosson
You could parse the string and build up a lambda expression using the Expressionclass, essentially duplicating the function of the compiler.
您可以解析字符串并使用Expression类构建一个 lambda 表达式,实质上是复制编译器的功能。
回答by Rasmus Faber
You might be able to do something with CSharpCodeProvider(wrap the expression with some more code to create a valid class and compile it into an assembly, then load the assembly).
您也许可以使用CSharpCodeProvider做一些事情(用更多代码包装表达式以创建有效的类并将其编译为程序集,然后加载程序集)。
I believe that is how LINQPaddoes it.
我相信这就是LINQPad 的做法。
回答by erikkallen
I guess you have to resort to the CSharpCodeProvider. However, dealing with all possible local variable references might not be trivial. And how would you tell the CSharpCodeProvider about the type of the lambda parameter? I would probably create a template class looking like this:
我猜你必须求助于 CSharpCodeProvider。但是,处理所有可能的局部变量引用可能并非易事。你如何告诉 CSharpCodeProvider 关于 lambda 参数的类型?我可能会创建一个看起来像这样的模板类:
class ExpressionContainer {
public Expression<Func<Product, bool>> TheExpression;
public string Length;
public ExpressionContainer() {
TheExpression = <user expression text>;
}
}
Then do something like this:
然后做这样的事情:
string source = <Code from above>;
Assembly a;
using (CSharpCodeProvider provider = new CSharpCodeProvider(...) {
List<string> assemblies = new List<string>();
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<CompilerError>().Select(e => e.ErrorText).ToArray()));
a = r.CompiledAssembly;
}
object o = a.CreateInstance("ExpressionContainer");
var result = ( Expression<Func<Product, bool>>)o.GetType().GetProperty("TheExpression").GetValue(o);
Note, however, that for long-running applications, you should create all these in-memory assemblies in a separate appdomain since they can't be freed until the appdomain they reside in is unloaded.
但是请注意,对于长时间运行的应用程序,您应该在单独的应用程序域中创建所有这些内存中程序集,因为在卸载它们所在的应用程序域之前无法释放它们。
回答by Prasad Kanaparthi
They are many lambda expression parsers available. Some of them are Lambda-Parser, Sprache
它们有许多可用的 lambda 表达式解析器。其中一些是Lambda-Parser,Sprache
Sample Code:
示例代码:
Example1 : string concat and number calculate:
示例1:字符串连接和数字计算:
string code = "2.ToString()+(4*2)"; // C# code Func<string>
func = ExpressionParser.Compile<Func<string>>(code); // compile code
string result = func(); // result = "28"
回答by Dave Cousineau
Responding to your more specific problem, (and you may already know this but I'll try mentioning it anyway), you could create a dictionary that maps values that can be a constant (integers or enums) to lambdas.
响应您更具体的问题(您可能已经知道这一点,但无论如何我都会尝试提及它),您可以创建一个字典,将可以是常量(整数或枚举)的值映射到 lambda。
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<Product, bool> mFunc;
public SecureAttribute(SecureFuncType pType) {
var secureFuncs = new Dictionary<SecureFuncType, Func<Product, bool>> {
{ 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...