C#将字符串转换为逻辑条件使用

16

是否有可能将一个字符串转换成运算符,以便在逻辑条件中使用。

例如:

if(x Convert.ToOperator(">") y) {}
或者
if(x ">" as Operator y){}

我很理解这可能不是标准问题,因此我对那些问我为什么要做这样的事情的答案不感兴趣。

提前感谢。

编辑:好的,我同意,给一些背景信息是公平的。

我们的系统是基于反射和XML构建的。 我想能够轻松地说些类似的话。

<Value = "Object1.Value" Operator = ">" Condition = "0"/>

编辑:感谢您的评论,我无法在此适当地解释这个问题。 我想我的问题得到了“你不能”的回答,这完全没有问题(也是我所想的)。 感谢您的评论。

编辑:算了,我要试一试。

想象以下情况

<Namespace.LogicRule Value= "Object1.Value" Operator=">" Condition="0">  

这将会被映射到一个类中,现在我想通过调用来测试条件:

bool LogicRule.Test()

那就是需要所有东西都能够齐头并进的部分。

编辑:

好的,在@jrista的建议之后,我第一次看了 Lambdas 或表达式。

我的系统允许解析枚举,因此由于ExpressionType枚举,表达式很有吸引力。

因此,我创建了以下类来测试这个想法:

    public class Operation
    {
        private object _Right;
        private object _Left;
        private ExpressionType _ExpressionType;
        private string _Type;

        public object Left
        {
            get { return _Left; }
            set { _Left = value; }
        }

        public object Right
        {
            get { return _Right; }
            set { _Right = value; }
        }

        public string Type
        {
            get { return _Type; }
            set { _Type = value; }
        }

        public ExpressionType ExpressionType
        {
            get { return _ExpressionType; }
            set { _ExpressionType = value; }
        }

        public bool Evaluate()
        {
            var param = Expression.Parameter(typeof(int), "left");
            var param2 = Expression.Parameter(typeof(int), "right");

            Expression<Func<int, int, bool>> expression = Expression.Lambda<Func<int, int, bool>>(
               Expression.MakeBinary(ExpressionType, param, param2), param, param2);

            Func<int, int, bool> del = expression.Compile();

            return del(Convert.ToInt32(Left), Convert.ToInt32(Right));

        }
    }

显然,目前只能针对Int32和基本的ExpressionTypes进行操作,我不确定能否使其泛化。我以前从未使用过Expressions,但这似乎能够运行。

然后,我们可以按照XML方式声明此方法:

Operation<Left="1" Right="2" ExpressionType="LessThan" Type="System.Int32"/>

我不会回答“你为什么这样做”的问题,但我会发表评论 :). 我只是好奇这对你的应用程序为什么很重要,不是想让你难受。 - JaredPar
1
@JaredPar:我经常看到这种情况:人们想将其存储在数据库中,并在以后的代码中检索使用。这并不意味着这是一个好主意,但这就是它的来源。 - Joel Coehoorn
谢谢您的更新,但是您想用那个XML做什么?它代表了什么意思?您是否想将该示例放在一个元素“q”中,并使用“if(Compare(q,x))”根据XML元素中表达的条件比较变量“x”? - John Saunders
@JaredPar:顺便提一下,OperatorCache<T> / 动态运算符分派是否可以解决这个问题? - Eoin Campbell
9个回答

14
你可以像这样做:

你可以这样做:

public static bool Compare<T>(string op, T x, T y) where T:IComparable
{
 switch(op)
 {
  case "==" : return x.CompareTo(y)==0;
  case "!=" : return x.CompareTo(y)!=0;
  case ">"  : return x.CompareTo(y)>0;
  case ">=" : return x.CompareTo(y)>=0;
  case "<"  : return x.CompareTo(y)<0;
  case "<=" : return x.CompareTo(y)<=0;
 }
}

6

编辑

正如JaredPar所指出的那样,我下面的建议不起作用,因为你不能将运算符应用于泛型...

因此,您需要为每个要比较/计算的类型具有特定的实现...

public int Compute (int param1, int param2, string op) 
{
    switch(op)
    {
        case "+": return param1 + param2;
        default: throw new NotImplementedException();
    }
}

public double Compute (double param1, double param2, string op) 
{
    switch(op)
    {
        case "+": return param1 + param2;
        default: throw new NotImplementedException();
    }
}

翻译

你可以像这样做。

你还需要尝试/捕获所有这些,以确保无论T是什么,都支持特定的操作。

我可以问一下为什么你可能需要这样做吗?你是在编写某种数学解析器吗?

public T Compute<T> (T param1, T param2, string op) where T : struct
{
    switch(op)
    {
        case "+":
            return param1 + param2;
        default:
             throw new NotImplementedException();
    }
}

public bool Compare<T> (T param1, T param2, string op) where T : struct
{
    switch (op)
    {
        case "==":
             return param1 == param2;
        default:
             throw new NotImplementedException();
    }
}

那会编译吗?我觉得不会。 - John Saunders
这是一种非常有限的方法。除了 == 和 != 之外,您不能在通用值上使用运算符。 - JaredPar
@John,可能不行,我是直接在SO窗口里涂鸦的,所以它有点半伪代码。@Jared。真的吗?好吧...放弃那个想法... :( - Eoin Campbell

3
不可能,你为什么要这样做?
当然,你可以创建一个类似以下的函数:
 public static bool Compare<T>(char op, T a, T b);

"op" 可能需要不止一个字符;你可以把 "!=" 或 "<>" 或 "==" 作为潜在的操作符。 - Adam V

3

您应该考虑使用.NET 3.5的表达式树。您可以手动构建表达式树(基本上是AST),然后调用Expression.Compile()来创建可调用委托。您的LogicRule.Test()方法需要构建表达式树,将树包装在一个LambdaExpression中,该LambdaExpression以您应用规则的对象作为参数,调用Compile()并调用生成的委托。


2

我曾经使用http://flee.codeplex.com/帮助完成类似的事情。

这个工具可以评估各种表达式。基本用法是传入一个字符串,例如“3>4”,该工具将返回false。

但是,您还可以创建一个求值器实例,并传入对象名称/值对,它可能会更加直观,例如:myObject^7 < yourObject。

在codeplex网站上,您可以深入了解更多功能。


1
你可以使用DynamicLinq来实现这个功能:
void Main()
{   
    var match = OpCompare(6, ">=", 4);  
    match.Dump();
}

private bool OpCompare<T>(T leftHand, string op, T rightHand)
{
    return new List<T>() { leftHand }.AsQueryable().Where($"it {op} {rightHand}").Any();
}

0

我认为你可以使用隐式转换来精确实现这一点。类似于:

   public static implicit operator Operator(string op) 
   {
      switch(op) {  
         case "==" : 
            return new EqualOperator();
            ...
      }
   }

   Operator op = "<";
   if( op.Compare(x,y) ) { ... }
   //or whatever use syntax you want for Operator.

0

Vici Parser(开源)可能对您有所帮助。它是一个C#表达式解析器,您只需传递包含表达式的字符串,即可获得计算结果。


-1
<Function = "PredicateMore" Param1 = "Object1.Value" Param2 = "0"/>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接