С# конвертировать строку для использования в логическом состоянии
Можно ли преобразовать строку в оператор для использования в логическом состоянии.
Например
if(x Convert.ToOperator(">") y) {}
или
if(x ">" as Operator y){}
Я ценю, что это может быть не вопрос стандартной практики, поэтому меня не интересуют ответы, которые спрашивают меня, почему, черт возьми, хотелось бы сделать что-то вроде этого.
Заранее спасибо
EDIT: ОК. Я согласен, справедлив, чтобы дать некоторый контекст.
У нас есть система, построенная вокруг отражения и XML. Я хотел бы сказать что-то вроде этого, для простоты.
<Value = "Object1.Value" Operator = ">" Condition = "0"/>
EDIT: Спасибо за ваши комментарии, я не могу правильно объяснить это здесь. На мой вопрос отвечает "Ты не можешь", что абсолютно нормально (и то, что я думал). Спасибо за ваши комментарии.
ИЗМЕНИТЬ: дерьмо, я собираюсь пойти.
Представьте себе следующее
<Namespace.LogicRule Value= "Object1.Value" Operator=">" Condition="0">
Это будет отражено в классе, поэтому теперь я хочу проверить условие, вызвав
bool LogicRule.Test()
Это бит, где все это должно собраться вместе.
EDIT:
Хорошо, поэтому, никогда не глядя на Лямбдас или выражения, я думал, что буду смотреть на предложения @jrista.
Моя система позволяет анализировать Enums, поэтому выражения являются привлекательными из-за EnpressionType Enum.
Итак, я создал следующий класс для проверки идеи:
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, я не уверен, что могу сделать его общим? Я никогда не использовал Expression раньше, но это, похоже, работает.
Этот способ может быть объявлен в нашем XML-способе как
Operation<Left="1" Right="2" ExpressionType="LessThan" Type="System.Int32"/>
Ответы
Ответ 1
Вы можете сделать что-то вроде этого:
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;
}
}
Ответ 2
ИЗМЕНИТЬ
Как отметил 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();
}
}
Ответ 3
Нет, это невозможно, и почему, черт возьми, вы сделали бы это?
Вы могли бы, конечно, создать такую функцию, как:
public static bool Compare<T>(char op, T a, T b);
Ответ 4
Вы должны изучить использование деревьев выражений .NET 3.5. Вы можете создавать выражения вручную в дереве выражений (в основном, AST), а затем вызывать Expression.Compile() для создания вызываемого делегата. Ваш метод LogicRule.Test() должен был бы построить дерево Expression, обернуть дерево в LambdaExpression, которое перенесет объект, применяющий правила, также как аргумент, вызывает Compile() и вызывает результирующий делегат.
Ответ 5
Я сделал нечто похожее на это с помощью:
http://flee.codeplex.com/
Этот инструмент может по существу вызывать широкий спектр выражений. Основное использование - это передать строку типа "3 > 4", и инструмент вернет false.
Однако вы также можете создать экземпляр оценщика и передать пары имя/значение объекта, и это может быть немного более интуитивно понятным IE: myObject ^ 7 < yourObject.
Существует более тонкая функциональность, на которую вы можете погрузиться на сайт codeplex.
Ответ 6
<Function = "PredicateMore" Param1 = "Object1.Value" Param2 = "0"/>
Ответ 7
Я думаю, вы можете добиться именно этого, используя неявное литье. Что-то вроде:
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.
Ответ 8
Vici Parser (open-source) может помочь вам. Это синтаксический анализатор С#, в котором вы можете просто передать строку, содержащую выражение, и получить полученный результат.