具有动态 LINQ 的 C# 布尔逻辑?
C# boolean logic with dynamic LINQ?
我一直在努力完成以下任务:
假设我有一个包含名称和值的列表(如字典)。我需要为 Web 界面的用户提供一个字段,他可以在其中编写查询,检查该列表中是否存在特定名称和值。
例如,我有以下列表:
A = 2, B = 4, D = 0
用户想这样查询这个列表(不要介意语法,它只是一个伪代码)
A == 2 && D
=> 这个 returns true
,因为 A
存在并且它的值是 2
并且 D
也存在。
(A && B) || C
=> 这个 returns true
,因为 A
和 B
都存在于列表中。
A && !B
=> 这个 returns false
,因为 A
存在于列表中,但 B
也存在(但 B
应该't)
我一直在寻找动态 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?
我已经复制了那里提供的代码并且它可以完美运行。没有动态代码(对我来说太难了),简单的二叉树。
感谢大家的参与。
我一直在努力完成以下任务:
假设我有一个包含名称和值的列表(如字典)。我需要为 Web 界面的用户提供一个字段,他可以在其中编写查询,检查该列表中是否存在特定名称和值。
例如,我有以下列表:
A = 2, B = 4, D = 0
用户想这样查询这个列表(不要介意语法,它只是一个伪代码)
A == 2 && D
=> 这个 returnstrue
,因为A
存在并且它的值是2
并且D
也存在。(A && B) || C
=> 这个 returnstrue
,因为A
和B
都存在于列表中。A && !B
=> 这个 returnsfalse
,因为A
存在于列表中,但B
也存在(但B
应该't)
我一直在寻找动态 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?
我已经复制了那里提供的代码并且它可以完美运行。没有动态代码(对我来说太难了),简单的二叉树。
感谢大家的参与。