具有动态 LINQ 的 C# 布尔逻辑?

C# boolean logic with dynamic LINQ?

我一直在努力完成以下任务:

假设我有一个包含名称和值的列表(如字典)。我需要为 Web 界面的用户提供一个字段,他可以在其中编写查询,检查该列表中是否存在特定名称和值。

例如,我有以下列表:

A = 2, B = 4, D = 0

用户想这样查询这个列表(不要介意语法,它只是一个伪代码)

我一直在寻找动态 LINQ,但似乎我一次只能评估一个对象(无法检查对象是否存在于列表中然后询问另一个对象是否存在'吨)。 有谁知道任何有用的材料或链接? 谢谢

不确定我是否理解你的要求...

这是你要的吗?

Dictionary<string, int> nameValuePairs = new Dictionary<string, int>();
        nameValuePairs.Add("A", 2);
        nameValuePairs.Add("B", 4);
        nameValuePairs.Add("D", 0);


        //A == 2 && D => this returns true, as A exists and it's value is 2 and D also exists
        int d = 0;
        if (nameValuePairs.ContainsKey("A") && nameValuePairs.TryGetValue("D", out d) && nameValuePairs.ContainsKey("D"))
        {
            Console.WriteLine("Test 1: True");
        }
        else
        {
            Console.WriteLine("Test 1: False");
        }

        //(A && B) OR C => this returns true, as both A and B exists on the list
        if ((nameValuePairs.ContainsKey("A") && nameValuePairs.ContainsKey("B")) || nameValuePairs.ContainsKey("C"))
        {
            Console.WriteLine("Test 2: True");
        }
        else
        {
            Console.WriteLine("Test 2: False");
        }

        //A && !B => this returns false, as A exists on the list but B as well (but B shouldn't)
        if (nameValuePairs.ContainsKey("A") && !nameValuePairs.ContainsKey("B")) 
        {
            Console.WriteLine("Test 3: True");
        }
        else
        {
            Console.WriteLine("Test 3: False");
        }

主要思想 - 您将创建 动态 代码(查看 GenerateCode 函数)就像字符串(它将是模拟你的表达式),然后将其编译为程序集。然后通过反射,你将采用特定方法 Calculate 并执行它。我创建了 Wrapper class (字典中的每个项目和数字都将被包装到其中),因为像“&”和“|”这样的操作int 类型不可能实现。

注意:"OR"你应该使用“&”、“|”而不是“&&”令牌或在计算前从客户端检索后替换它们。

代码:

using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication5
{
    public class Program
    {
        public static string GenerateCode(Dictionary<string, int> dict, string expres)
        {
            var r = new Regex(@"-?\d+");
            foreach (var item1 in r.Matches(expres))
                expres = expres.Replace(item1.ToString(), string.Format("(new Wrapper({0}))", item1.ToString()));

            r = new Regex("[A-Z]");
            var res = "";
            var areadyDone = new List<string>();

            foreach (var item in r.Matches(expres))
            {
                var key = item.ToString();
                if (!areadyDone.Contains(key))
                {
                    res += string.Format("var {0} = new Wrapper({1});\n", item, dict.ContainsKey(key) ? dict[key].ToString() : "");
                    areadyDone.Add(key);
                }
            }

            return string.Format("{0}return {1};", res, expres);
        }

        public static bool GetAnswer(Dictionary<string, int> dict, string expres)
        {
            string code = @"
using System;

    namespace First
    {

public class Wrapper
    {
        public int value;
        public bool exist = false;
        public Wrapper(int value)
        {
            this.value = value;
            this.exist = true;
        }
        public Wrapper()
        {
        }

        private static bool wrap(Wrapper c1, Wrapper c2, bool cond)
        {
            return (c1 & c2) ? cond : false;
        }

        public static bool operator &(Wrapper c1, Wrapper c2)
        {
            return c1.exist && c2.exist;
        }
        public static bool operator |(Wrapper c1, Wrapper c2)
        {
            return c1.exist || c2.exist;
        }
        public static bool operator !(Wrapper c1)
        {
            return !c1.exist;
        }
        public static implicit operator bool(Wrapper d)
        {
            return d.exist;
        }

        public static bool operator >(Wrapper c1, Wrapper c2)
        {
            return wrap(c1, c2, c1.value > c2.value);
        }
        public static bool operator <(Wrapper c1, Wrapper c2)
        {
            return wrap(c1, c2, c1.value < c2.value);
        }
        public static bool operator >=(Wrapper c1, Wrapper c2)
        {
            return wrap(c1, c2, c1.value >= c2.value);
        }
        public static bool operator <=(Wrapper c1, Wrapper c2)
        {
            return wrap(c1, c2, c1.value <= c2.value);
        }

        public static bool operator ==(Wrapper c1, Wrapper c2)
        {
            return wrap(c1, c2, c1.value == c2.value);
        }
        public static bool operator !=(Wrapper c1, Wrapper c2)
        {
            return wrap(c1, c2, c1.value != c2.value);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

    }


        public class Program
        {
            public static bool Calculate()
            {
            " + GenerateCode(dict, expres) + @"
            }

            public static void Main()
            {  
            }

        }
    }";
            var provider = new CSharpCodeProvider();
            var parameters = new CompilerParameters();

            parameters.GenerateInMemory = true;
            parameters.GenerateExecutable = true;

            var results = provider.CompileAssemblyFromSource(parameters, code);
            if (results.Errors.HasErrors)
            {
                var sb = new StringBuilder();
                foreach (CompilerError error in results.Errors)
                    sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
                throw new InvalidOperationException(sb.ToString());
            }
            else
            {
                var assembly = results.CompiledAssembly;
                var program = assembly.GetType("First.Program");
                var main = program.GetMethod("Calculate");
                return (bool)main.Invoke(null, null);
            }
        }

        public static void Main()
        {
            var dict = new Dictionary<string, int>();
            dict.Add("A", 23);
            dict.Add("B", 4);
            dict.Add("F", 5);

            Console.WriteLine(GetAnswer(dict, "(C > -5) | (A >= 10 & B)"));
        }
    }
}

好的,实际上 Heinzi 回答了我的问题,指出有一个问题可以回答我的问题:How to parse a boolean expression and load it into a class?

我已经复制了那里提供的代码并且它可以完美运行。没有动态代码(对我来说太难了),简单的二叉树。

感谢大家的参与。