Передача оператора вместе с другими параметрами
У меня есть ОЧЕНЬ неэффективный код, в котором многие строки появляются 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
}
}