2009-05-29 7 views
12

Czy jest możliwe przekonwertowanie ciągu znaków na operator w celu użycia w stanie logicznym.C# przekonwertuj ciąg znaków do użycia w stanie logicznym.

Na przykład

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

lub

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

Rozumiem, że to może nie być standardową praktyką pytanie, więc nie jestem zainteresowany w odpowiedzi, które pytają mnie, dlaczego, do cholery, chciałby zrobić coś takiego.

góry dzięki

EDIT: OK, zgadzam się, tylko uczciwie dać pewien kontekst.

Mamy system zbudowany wokół odbicia i XML. Chciałbym móc powiedzieć coś takiego, dla ułatwienia.

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

EDYCJA: Dziękuję za komentarze, nie mogę tego dokładnie wyjaśnić tutaj. Domyślam się, że na moje pytanie odpowiada "Nie możesz", co jest absolutnie w porządku (i co myślałem). Dzięki za twoje komentarze.

EDYCJA: Sod it I'll have a go.

Wyobraźmy sobie następujący

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

To będzie odzwierciedlone w klasie, więc teraz chcę przetestować warunek, wywołując

bool LogicRule.Test() 

To nieco gdzie to wszystko trzeba przyjść razem.

EDIT:

OK, więc nigdy nie spojrzał na lambdas lub wyrażenia myślałem, że mam opiekować użytkownika @ jrista sugestie.

Mój system umożliwia analizowanie wyliczeń, więc wyrażenia są atrakcyjne z powodu wyrażeń ExpressionType.

Stworzyłem więc następujące klasy przetestować pomysł:

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

     } 
    } 

Oczywiście to będzie działać tylko dla Int32 teraz i podstawowe ExpressionTypes, nie jestem pewien, czy mogę zrobić to generyczny? Nigdy wcześniej nie używałam Wyrażeń, ale wydaje się, że działa.

W ten sposób mogą być zadeklarowane w naszej XML sposób

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

Nie odpowiem "dlaczego to robisz", ale zamiast tego skomentuję to :). Nie próbując być bólem, jestem tylko ciekawy, dlaczego jest to ważne dla twojej aplikacji. – JaredPar

+1

@JaredPar: Widzę to cały czas: ludzie, którzy chcą przechowywać go w db i pobrać go do wykorzystania w kodzie później. To nie znaczy, że to dobry pomysł, ale właśnie z tego pochodzi. –

+0

Dzięki za aktualizację, ale co chcesz zrobić z tym XML-em i co to znaczy? Czy chcesz mieć ten przykład w elemencie "q" i czy "if (Compare (q, x))" by porównać zmienną "x" zgodnie ze stanem wyrażonym w elemencie XML? –

Odpowiedz

11

Można zrobić coś takiego:

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; 
} 
} 
4

Nie, to nie jest to możliwe, i dlaczego, do cholery, byś przeciwnym razie możesz to zrobić?

Można było oczywiście stworzenie funkcji takich jak:

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

"Op" może wymagać więcej niż char; możesz mieć "! =" lub "<>" lub "==" jako potencjalnych operatorów. –

5

EDIT

JaredPar Jak podkreślił, moja sugestia poniżej nie będzie działać, ponieważ nie można stosować operatorów rodzajowych ...

Więc trzeba by mieć konkretne implementacje dla każdego rodzaju Państwo chcieli porównać/obliczyć ...

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

Można zrobić coś takiego.

Musisz też spróbować/złapać to wszystko, aby upewnić się, że niezależnie od tego, co T, obsługuje konkretne operacje.

Pamiętaj, jeśli zapytam, dlaczego musiałbyś to zrobić. Czy piszesz jakiś matematyczny 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(); 
    } 
} 
+0

Czy to się skompiluje? Nie sądzę. –

+0

Jest to jednak bardzo ograniczone podejście. Poza == i! = Nie możesz używać operatorów na ogólnych wartościach. – JaredPar

+0

@John, prawdopodobnie nie, zapisałem go bezpośrednio w oknie SO, więc jest pół pseudo @Jared. Naprawdę? ok ... zdrap ten pomysł ... :( –

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

myślę, że można osiągnąć dokładnie to za pomocą implicit casting. Coś jak:

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. 
2

Robiłem coś podobnego do tego z pomocą:

http://flee.codeplex.com/

To narzędzie może zasadniczo evaulate szeroki zakres wyrażeń. Podstawowym zastosowaniem byłoby przekazanie ciągu takiego jak "3> 4", a narzędzie zwróciło wartość false.

Można jednak również utworzyć instancję oceniającego i przekazać pary nazwa/wartość obiektu, co może być nieco bardziej intuicyjne IE: myObject^7 < yourObject.

Istnieje więcej funkcji, które można zanurkować na stronie codeplex.

3

Powinieneś zajrzeć do drzewa wyrażeń .NET 3.5. Możesz budować wyrażenia ręcznie do drzewa wyrażeń (w zasadzie AST), a następnie wywoływać wyrażenie Expression.Compile(), aby utworzyć przywoływanego delegata. Twoja metoda LogicRule.Test() będzie musiała zbudować drzewo Expression, zawinąć drzewo w LambdaExpression, które pobiera obiekt, stosując reguły również jako argument, wywołuje funkcję Compile() i wywołuje wynikową delegację.

0

Vici Parser (open-source) może być pomocne dla Ciebie. Jest to analizator wyrażeń C#, w którym można po prostu przekazać ciąg zawierający wyrażenie i uzyskać obliczony wynik z powrotem.