16

Is it possible to convert a string to an operator for use in a logical condition.

For example

if(x Convert.ToOperator(">") y) {}

or

if(x ">" as Operator y){}

I appreciate that this might not be standard practice question, therefore I'm not interested in answers that ask me why the hell would want to do something like this.

Thanks in advance

EDIT: OK I agree, only fair to give some context.

We have system built around reflection and XML. I would like to be able to say something like, for ease.

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

EDIT: Thanks for your comments, I can't properly explain this on here. I guess my question is answered by "You can't", which is absolutely fine (and what I thought). Thanks for your comments.

EDIT: Sod it I'm going to have a go.

Imagine the following

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

This will get reflected into a class, so now I want to test the condition, by calling

bool LogicRule.Test()

That's the bit where it would all need to come together.

EDIT:

OK, so having never looked at Lambdas or Expressions I thought I would have a look after @jrista's suggestions.

My system allows Enums to be parsed, so Expressions are attractive because of the ExpressionType Enum.

So I created the following class to test the idea:

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

        }
    }

Obviously this will only work for Int32 right now and the basic ExpressionTypes, I'm not sure I can make it generic? I've never use Expressions before, however this seems to work.

This way can then be declared in our XML way as

Operation<Left="1" Right="2" ExpressionType="LessThan" Type="System.Int32"/>
4
  • I won't answer "why are you doing this" but I will comment it instead :). Not trying to be a pain, I'm just curious as to why this is important to your application. Commented May 29, 2009 at 13:16
  • 1
    @JaredPar: I see this all the time: people wanting to store it in a db and retrieve it for use in code later. Doesn't mean it's a good idea, but that's where it comes from. Commented May 29, 2009 at 13:18
  • Thanks for the update, but what do you want to do with that XML, and what does it mean? Do you want to have that example in an element, "q", and do "if (Compare(q,x))" to compare variable "x" according to the condition expressed in the XML element? Commented May 29, 2009 at 13:24
  • @JaredPar: as a side note, is this something that OperatorCache<T> / Dynamic Operator Dispatch could solve ? Commented May 29, 2009 at 13:50

9 Answers 9

14

You could do something like this:

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;
 }
}
Sign up to request clarification or add additional context in comments.

Comments

6

EDIT

As JaredPar pointed out, my suggestion below won't work as you can't apply the operators to generics...

So you'd need to have specific implementations for each types you wanted to compare/compute...

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

ORIG

You could do something like this.

You'd also need to try/catch all this to ensure that whatever T is, supports the particular operations.

Mind if I ask why you would possibly need to do this. Are you writing some sort of mathematical parser ?

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

3 Comments

Is that going to compile? I don't think so.
This is a very limited approach though. Outside of == and != you cannot use operators on generic values.
@John, probably not, I scribbled it directly into the SO window so it's semi-pseudo @Jared. Really ? ok... scratch that Idea... :(
3

No, it's not possible, and why the hell would you wnat to do this?

You could, of course, create a function like:

 public static bool Compare<T>(char op, T a, T b);

1 Comment

The "op" might need to be more than a char; you can have "!=" or "<>" or "==" as potential operators.
3

You should look into using .NET 3.5's Expression trees. You can build expressions manually into an expression tree (basically an AST), and then call Expression.Compile() to create a callable delegate. Your LogicRule.Test() method would need to build the Expression tree, wrap the tree in a LambdaExpression that takes the object your applying the rules too as an argument, calls Compile(), and invokes the resulting delegate.

Comments

2

I've done something similar to this with the help of:

http://flee.codeplex.com/

This tool can essentially evaulate a wide range of expressions. Basic usage would be to pass in a string like '3 > 4' and the tool would return false.

However, you can also create an instance of the evaluator and pass in object name/value pairs and it can be a little more intuitive IE: myObject^7 < yourObject.

There is a ton more functionality that you can dive into at the codeplex site.

Comments

1

You can use DynamicLinq for this:

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

Comments

0

I think you can achieve exactly this using implicit casting. Something like:

   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.

Comments

0

Vici Parser (open-source) may be of help to you. It's a C# expression parser where you can just pass a string containing an expression, and you get the computed result back.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.