2009-07-27 10 views
10

Mam bardzo BARDZO nieefektywny kod, w którym wiele linii pojawia się 4 razy, gdy przechodzę przez permutacje operacjami "<" i ">" oraz różnymi zmiennymi i stałymi. Wydaje się, że istnieje sposób, aby raz napisać funkcję i przekazać operatorom wraz z koniecznie zmieniającymi się wartościami i zmiennymi "ref". Jakiej techniki muszę się nauczyć? "Delegaci" zostały zasugerowane, ale nie widzę sposobu ich używania w ten sposób. To jest w C# 2.0, VS2005, ale jeśli technika jest ogólna i może być używana również z C++, byłoby świetnie.Przekazywanie operatora wraz z innymi parametrami

Zapytanie o jakimś kodzie: Poniżej pojawia się w wielu postaciach, z różnych „<” i „>” znaki, jak również mieszanki „+” i „-” znaki:

if (move[check].Ypos - move[check].height/200.0D < LayoutManager.VISIO_HEIGHT - lcac_c.top) 
{ 
    move[check].Ypos = move[check].Ypos + adjust; 
. 
. 
. 
+2

Byłbyś w stanie opublikować jakiś kod? –

+0

Czy ktoś mógłby sformatować ten kod? Czy możesz podać nam trochę więcej kodu? W tej chwili trudno zobaczyć, co się zmieni - Czy zawsze będzie przeciwko "move [check]" i skąd pochodzi "adjust"? Twoje obecne przypuszczenie przy metodzie podpisu może pomóc. –

+0

Dzięki Robowi za wyczyszczenie widoczności mojego kodu! "Dostosuj" jest zmienną klasy i zmieniam ją w zależności od rozdzielczości ekranu i komputera, na którym demo programu. move to tablica wystąpień klasy W 2 z 4 wariantów kodu chciałbym uzyskać Xpos, a nie YPos. Również 2 z 4 mają <, 2 have >. Wszystko za pomocą> użyłoby + przed zmienną regulującą i na odwrót. Ponadto, jeden używa lcac_c.top, jeden używa lcac_c.right, itp. Chciałbym, aby wszystkie te zostały przekazane. – user32848

Odpowiedz

11

W C++, użyj std::less i std::greater funktory. Obie te metody dziedziczą std::binary_function, więc Twoja funkcja ogólna powinna akceptować wystąpienia tego typu.

W .NET, odpowiednikiem std::binary_function jest Func<T, U, R>. Nie ma odpowiedników dla std::less i std::greater, ale tworzenie ich jest dość banalne. Zobacz następujący przykład.

static class Functor 
{ 
    static Func<T, T, bool> Greater<T>() 
     where T : IComparable<T> 
    { 
     return delegate(T lhs, T rhs) { return lhs.CompareTo(rhs) > 0; }; 
    } 

    static Func<T, T, bool> Less<T>() 
     where T : IComparable<T> 
    { 
     return delegate(T lhs, T rhs) { return lhs.CompareTo(rhs) < 0; }; 
    } 
} 

Uwaga, powyższy kod wykorzystuje klasę Func<> z .NET 3.5. Jeśli nie jest to dopuszczalne, rozważ zdefiniowanie własnego delegata.

C++ przykład inwokacja:

void DoWork(const std::binary_function<int, int, bool>& myOperator, 
      int arg1, int arg2) 
{ 
    if (myOperator(arg1, arg2)) { /* perform rest of work */ } 
} 

void main() 
{ 
    DoWork(std::less<int>(), 100, 200); 
    DoWork(std::greater<int>(), 100, 200); 
} 

C Przykład # inwokacja:

void DoWork(Func<int, int, bool> myOperator, int arg1, int arg2) 
{ 
    if (myOperator(arg1, arg2)) { /* perform rest of work */ } 
} 

void main() 
{ 
    DoWork(Functor.Less<int>(), 100, 200); 
    DoWork(Functor.Greater<int>(), 100, 200); 
} 

EDIT: poprawiłem przykład klasy funktora jako odnoszące < lub> operatorom typu rodzajowego robi” t działa (w taki sam sposób jak w szablonach C++).

+1

To jest o wiele lepsza odpowiedź niż moja. –

+0

W powyższym przykładzie C#, czy Functor jest dostępny w .Net 2.0? Nie mogę sprawić, aby powyższy kod działał? Czy muszę dodać referencję? – user32848

+0

Nie, Functor nie jest standardową klasą .NET - musisz napisać to sam. Ponadto, .NET 2.0 nie zawiera Func <> (jest w System.Core.dll w .NET 3.5), więc będziesz musiał użyć System.Predicate na swoim miejscu. –

2

w C# użyj delegatów do przekazania operacji "<" i ">" do kodu wykonującego pracę.

C# Przykład:

public delegate bool BooleanOperatorDelegate(int a, int b) 

class OperatorsImplementer { 
    public bool OperatorLess(int a, int b) { 
     return a < b; 
    } 
} 

class AnotherOperatorsImplementer { 
    public bool OperatorLess(int a, int b) { 
     return (a + 1) < (b - 1); 
    } 
} 

class OperatorUser { 
    int DoSomethingObscene(int a, int b, BooleanOperatorDelegate operator) { 
     if (operator(a, b)) { 
      return 5; 
     } 
     else { 
      return -5; 
     } 
    } 
} 

Należy również sprawdzić, czy delegat masz jako paramater nie jest NULL.

Jest to metoda C za to:

bool (*operator_func)(float a, float b) 
+0

Idiomatic C++ faktycznie używa obiektów funkcji, a nie wskaźników funkcji (w szczególności umożliwiłoby to użycie 'std: less' i innych takich funktorów giełdowych). –

0

Możesz przekazać operatorów, definiując je w podobny sposób, jak Operator Enum w tej klasie Comparer; a następnie wywołać funkcję tak:

if (IsTrue(var1, Operator.GreaterThanOrEqual, var2)) 
    Console.WriteLine("var1 is greater than var2"); 
else 
    Console 
     .WriteLine("Unfortunately var1 is not greater than or equal var2. Sorry about that."); 

 public static class Comparer 
{ 
    public static bool IsTrue<T, U>(T value1, Operator comparisonOperator, U value2) 
       where T : U 
       where U : IComparable 
    { 
     switch (comparisonOperator) 
     { 
      case Operator.GreaterThan: 
       return value1.CompareTo(value2) > 0; 
      case Operator.GreaterThanOrEqual: 
       return value1.CompareTo(value2) >= 0; 
      case Operator.LessThan: 
       return value1.CompareTo(value2) < 0; 
      case Operator.LessThanOrEqual: 
       return value1.CompareTo(value2) <= 0; 
      case Operator.Equal: 
       return value1.CompareTo(value2) == 0; 
      default: 
       return false; 
     } 
    } 

    public enum Operator 
    { 
     GreaterThan = 1, 
     GreaterThanOrEqual = 2, 
     LessThan = 3, 
     LessThanOrEqual = 4, 
     Equal = 5 
    } 
} 
+0

Należy rozważyć dodanie niektórych szczegółów i wyjaśnień, aby wesprzeć odpowiedź, aby pomóc innym –

Powiązane problemy