Передача оператора вместе с другими параметрами

У меня есть ОЧЕНЬ неэффективный код, в котором многие строки появляются 4 раза, когда я перехожу через перестановки с "<" и " > ", а также различные переменные и константы. Казалось бы, есть способ написать функцию один раз и передать в операторы вместе с обязательно меняющимися значениями и "ref" переменными. Какую технику я должен изучить? "Делегаты" были предложены, но я не вижу, как их использовать таким образом. Это в С# 2.0, VS2005, но если метод является общим и может использоваться с С++ тоже, это было бы здорово.

Запрос на некоторый код: Во многих обличьях появляется следующее: с разными символами < и " > ", а также сочетание знаков "+" и "-":

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

Ответ 1

В С++ используйте std::less и std::greater. Оба этих метода наследуют std::binary_function, поэтому ваша общая функция должна принимать экземпляры этого типа.

В .NET эквивалент std::binary_function Func<T, U, R>. Для std::less и std::greater нет эквивалентов, но их создание довольно тривиально. См. Следующий пример.

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

Примечание. В приведенном выше коде используется класс Func<> из .NET 3.5. Если это неприемлемо, подумайте об определении собственного делегата.

Пример вызова С++:

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

Пример вызова С#:

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: я исправил пример класса функтора, применяя < или > для родового типа не работает (так же, как и с шаблонами С++).

Ответ 2

В С# используйте делегаты для передачи операции "<" и ">" коду, выполняющему работу.

С# Пример:

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

Вы также должны проверить, что делегат, который вы получаете как параметр, не равен NULL.

Это метод C для этого:

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

Ответ 3

Вы можете передавать операторы, определяя их аналогично оператору Enum в этом классе Comparer; а затем вызовите функцию следующим образом:

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