C# 从字符串创建 lambda 表达式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8857871/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 04:50:03  来源:igfitidea点击:

Creating lambda expression from a string

c#linqlambda

提问by ideafountain

Possible Duplicate:
Is there an easy way to parse a (lambda expression) string into an Action delegate?

可能的重复:
是否有一种简单的方法可以将(lambda 表达式)字符串解析为 Action 委托?

I would like to store lambda expressions as strings in a config file and at runtime dynamically load these strings into lambda expressions in C#. My objective is to configure and inject rules. Any utilities available for creating lambda expressions from a string ?

我想将 lambda 表达式作为字符串存储在配置文件中,并在运行时将这些字符串动态加载到 C# 中的 lambda 表达式中。我的目标是配置和注入规则。任何可用于从字符串创建 lambda 表达式的实用程序?

Are there any other light weight solutions for the same objective ?

对于同一目标,是否还有其他轻量级解决方案?

回答by James Manning

If you know the type of the expressions ahead of time, then you can compile them as part of a class then pull them back out from the resulting assembly.

如果您提前知道表达式的类型,那么您可以将它们编译为类的一部分,然后将它们从生成的程序集中取出。

Here's an example that does (with the expressions taking a string and returning a bool) that and runs the resulting rules.

这是一个示例(表达式接受一个字符串并返回一个布尔值)并运行结果规则。

With the contents of c:\temp\rules.txt being this:

与 c:\temp\rules.txt 的内容是这样的:

file => file.Length == 0
file => System.IO.Path.GetExtension(file) == ".txt"
file => file == null

Then the resulting output is this:

然后结果输出是这样的:

Rules found in file:
file => file.Length == 0,
file => System.IO.Path.GetExtension(file) == ".txt",
file => file == null,

Checking rule file => (file.Length == 0) against input c:\temp\rules.txt: False
Checking rule file => (GetExtension(file) == ".txt") against input c:\temp\rules.txt: True
Checking rule file => (file == null) against input c:\temp\rules.txt: False

Source:

来源:

using System;
using System.Xml.Linq;
using System.Linq;
using System.IO;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Linq.Expressions;

class Program
{
    private const string classTemplate = @"
            using System;
            using System.Linq.Expressions;

            public static class RulesConfiguration
            {{
                private static Expression<Func<string, bool>>[] rules = new Expression<Func<string, bool>>[]
                {{
                    {0}
                }};

                public static Expression<Func<string, bool>>[] Rules {{ get {{ return rules; }} }}
            }}
        ";

    static void Main(string[] args)
    {
        var filePath = @"c:\temp\rules.txt";
        var fileContents = File.ReadAllLines(filePath);

        // add commas to the expressions so they can compile as part of the array
        var joined = String.Join("," + Environment.NewLine, fileContents);

        Console.WriteLine("Rules found in file: \n{0}", joined);

        var classSource = String.Format(classTemplate, joined);

        var assembly = CompileAssembly(classSource);

        var rules = GetExpressionsFromAssembly(assembly);

        foreach (var rule in rules)
        {
            var compiledToFunc = rule.Compile();
            Console.WriteLine("Checking rule {0} against input {1}: {2}", rule, filePath, compiledToFunc(filePath));
        }
    }

    static Expression<Func<string, bool>>[] GetExpressionsFromAssembly(Assembly assembly)
    {
        var type = assembly.GetTypes().Single();
        var property = type.GetProperties().Single();
        var propertyValue = property.GetValue(null, null);
        return propertyValue as Expression<Func<string, bool>>[];
    }

    static Assembly CompileAssembly(string source)
    {
        var compilerParameters = new CompilerParameters()
        {
            GenerateExecutable = false,
            GenerateInMemory = true,
            ReferencedAssemblies =
            {
                "System.Core.dll" // needed for linq + expressions to compile
            },
        };
        var compileProvider = new CSharpCodeProvider();
        var results = compileProvider.CompileAssemblyFromSource(compilerParameters, source);
        if (results.Errors.HasErrors)
        {
            Console.Error.WriteLine("{0} errors during compilation of rules", results.Errors.Count);
            foreach (CompilerError error in results.Errors)
            {
                Console.Error.WriteLine(error.ErrorText);
            }
            throw new InvalidOperationException("Broken rules configuration, please fix");
        }
        var assembly = results.CompiledAssembly;
        return assembly;
    }
}

回答by Felice Pollano

Have a look at Dynamic Linq. It's an old post but always useful.

看看动态 Linq。这是一个旧帖子,但总是有用的。