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

时间:2016-01-28 12:12:10

标签: c# .net linq linq-to-objects

我对以下任务感到困惑:

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

例如,我有以下列表:

A = 2, B = 4, D = 0

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

  • A == 2 && D =>这将返回true,因为A存在且其值为2D也存在。
  • (A && B) || C =>这会返回true,因为列表中存在AB
  • A && !B =>这会返回false,因为A存在于列表中,但B也是如此(但B不应该

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

3 个答案:

答案 0 :(得分:3)

不确定我是否了解您的要求......

这就是你要求的吗?

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");
        }

答案 1 :(得分:0)

主要想法 - 您将创建动态代码(查看GenerateCode函数),就像字符串一样(它将与您的表达式类似)然后编译它组装。然后通过反射,您将采用特定方法Calculate并执行它。我创建了Wrapper类(字典和数字中的每个项目都将包含在其中),因为像&#34;&amp;&#34;和&#34; |&#34; int类型无法实现。

注意:取代&#34;&amp;&amp;&#34;,&#34; OR&#34;你应该使用&#34;&amp;&#34;,&#34; |&#34;在计算之前从客户端检索后更换或替换它们。

<强>代码:

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)"));
        }
    }
}

答案 2 :(得分:0)

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

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

谢谢大家的参与。