2009-07-27 10 views
10

Tengo un código MUY ineficiente en el que muchas líneas aparecen 4 veces a medida que paso por permutaciones con operaciones "<" y ">" y una variedad de variables y constantes. Parecería que hay una forma de escribir la función una vez y pasar los operadores junto con los valores necesariamente cambiantes y las variables "ref". ¿Qué técnica debo aprender? Se han sugerido "delegados" pero no veo cómo usarlos de esta manera. Esto está en C# 2.0, VS2005, pero si la técnica es genérica y también se puede usar con C++, sería genial.Pasando un operador junto con otros parámetros

Solicitud de algo de código: El siguiente aparece en muchas formas, con diferentes "<" signos y ">", así como una mezcla de "+" y "-" signos:

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

¿Sería capaz de enviar un código? –

+0

¿Alguien podría formatear ese código? Además, ¿podría darnos un poco más de código? En este momento es difícil ver qué variará todo: ¿siempre estará en contra de 'movimiento [check]', y de dónde viene 'adjust'? Su conjetura actual sobre la firma de un método puede ayudar. –

+0

¡Gracias a Rob por limpiar la visibilidad de mi código! "ajustar" es una variable de clase y la cambio dependiendo de la resolución de pantalla y la computadora en la que estoy demostrando el programa. mover es una matriz de instancias de una clase En 2 de las 4 variantes del código, nos gustaría Xpos, no YPos. También 2 de los 4 tienen <, 2 have >. Cualquier cosa con> usaría un + antes de la variable de ajuste y viceversa. Además, uno usa lcac_c.top, uno usa lcac_c.right, etc. Quisiera que se pasen todos estos. – user32848

Respuesta

11

En C++, utilice las std::less y std::greater funtores. Ambos métodos heredan std::binary_function, por lo que su función genérica debería aceptar instancias de este tipo.

En .NET, el equivalente a std::binary_function es Func<T, U, R>. No hay equivalentes en std::less y std::greater, pero es bastante trivial crearlos. Vea el siguiente ejemplo.

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

Nota, el código anterior utiliza la clase Func<> de .NET 3.5. Si esto no es aceptable, considere definir su propio delegado.

C++ ejemplo invocación:

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 Ejemplo # invocación:

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

EDITAR: corregí el ejemplo de la clase funtor como la aplicación < o> operadores a un tipo genérico doesn' t trabajo (de la misma manera que lo hace con las plantillas de C++).

+1

Esta es una respuesta mucho mejor que la mía. –

+0

En el ejemplo de C# anterior, ¿está Functor disponible en .Net 2.0? No puedo hacer que el código anterior funcione? ¿Debo agregar una referencia? – user32848

+0

No, Functor no es una clase .NET estándar; debe escribirlo usted mismo. Además, .NET 2.0 no contiene Func <> (está en System.Core.dll en .NET 3.5), por lo que deberá usar System.Predicate en su lugar. –

2

en C# utilice delegados para pasar la operación "<" y ">" al código que está haciendo el trabajo.

C# Ejemplo:

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

También debe comprobar que el delegado que se obtiene como un parámetro de no es NULL.

Este es el método C para hacerlo:

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

Idiomatic C++ realmente usaría objetos de función y no punteros de función (en particular, esto permitiría el uso de 'std: less' y otros funcionamientos de stock de ese tipo). –

0

Puede pasar operadores definiéndolos de manera similar al operador Enum en esta clase Comparer; y luego llamar a la función como esta:

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

Considere agregar algunos detalles y explicaciones para respaldar su respuesta a fin de ayudar a los demás –

Cuestiones relacionadas