C # преобразовать строку для использования в логическом условии - PullRequest
14 голосов
/ 29 мая 2009

Возможно ли преобразовать строку в оператор для использования в логическом условии.

Например

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

Это та часть, где все это должно было бы собраться вместе.

EDIT:

Хорошо, поэтому, никогда не глядя на Lambdas или Expressions, я подумал, что взгляну на предложения @ jrista.

Моя система позволяет анализировать перечисления, поэтому выражения привлекательны из-за перечисления 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, я не уверен, что смогу сделать его универсальным? Я никогда не использовал выражения раньше, однако, похоже, это работает.

Этот способ может быть объявлен в нашем XML-формате как

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

Ответы [ 8 ]

13 голосов
/ 29 мая 2009

Вы можете сделать что-то вроде этого:

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;
 }
}
5 голосов
/ 29 мая 2009

EDIT

Как указал 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();
    }
}

ORIG

Вы могли бы сделать что-то подобное.

Вам также нужно попробовать / перехватить все это, чтобы убедиться, что какой-либо 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();
    }
}
4 голосов
/ 29 мая 2009

Нет, это невозможно, и какого черта вы не захотите это сделать?

Конечно, вы можете создать такую ​​функцию:

 public static bool Compare<T>(char op, T a, T b);
3 голосов
/ 29 мая 2009

Вы должны изучить использование деревьев выражений .NET 3.5. Вы можете построить выражения вручную в дереве выражений (в основном, AST), а затем вызвать Expression.Compile () для создания вызываемого делегата. Ваш метод LogicRule.Test () должен был бы построить дерево выражений, обернуть дерево в выражение LambdaExpression, которое принимает объект, применяющий ваши правила, в качестве аргумента, вызывает Compile () и вызывает полученный делегат.

2 голосов
/ 29 мая 2009

Я сделал нечто подобное с помощью:

http://flee.codeplex.com/

Этот инструмент может существенно оценить широкий спектр выражений. Основное использование - передать строку типа «3> 4», и инструмент вернет false.

Однако вы также можете создать экземпляр оценщика и передать пары имя / значение объекта, и это может быть немного более интуитивным IE: myObject ^ 7

Существует гораздо больше функциональных возможностей, которые вы можете использовать на сайте codeplex.

0 голосов
/ 01 июня 2009

Vici Parser (с открытым исходным кодом) может помочь вам. Это синтаксический анализатор выражений C #, в котором вы можете просто передать строку, содержащую выражение, и получить вычисленный результат обратно.

0 голосов
/ 29 мая 2009

Я думаю, вы можете достичь именно этого, используя неявное приведение Что-то вроде:

   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 голосов
/ 29 мая 2009
<Function = "PredicateMore" Param1 = "Object1.Value" Param2 = "0"/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...