В Mac OS X и Windows есть встроенные функции CompareAndSwap, которые вы должны использовать в любом случае (InterlockedCompareExchange () и OSAtomicCompareAndSwapPtrBarrier () соответственно). Таким образом, будет работать независимо от компиляторов на этих платформах.
В других Unix-системах это немного сложнее, если вы используете GCC 4.1 или новее, вы можете просто использовать его встроенную функцию __sync_val_compare_and_swap (), и многие, хотя и не все компиляторы Unix, поддерживают разумные расширения gcc, так как большая часть кода начинается в Linux предполагается, что они присутствуют.
Поэтому, если вы хотите обернуть их так, чтобы они работали практически со всеми компиляторами для всех процессоров в OS X и Windows, а также с GCC и некоторыми другими компиляторами на других платформах, вам следует сделать что-то вроде:
boolean CompareAndSwapPointer(volatile * void * ptr,
void * new_value,
void * old_value) {
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
return OSAtomicCompareAndSwapPtr (old_value, new_value, ptr);
#elif defined(_MSC_VER)
return InterlockedCompareExchange(ptr, new_value, old_value);
#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
return __sync_val_compare_and_swap(ptr, old_value, new_value);
#else
# error No implementation
#endif
}
Это не проверено, но я думаю, что это должно быть правильно. Обратите внимание, как все библиотеки ОС принимают аргументы в разных порядках; -)
Очевидно, что вы можете сделать несколько версий для сравнения разного размера, а также поменять их и обернуть в шаблоны, если хотите. API-интерфейсы в основном основаны на C и кодируют информацию о типах в функции таким образом, что это немного неприятно для людей, привыкших параметризировать типы с помощью шаблонов.
Вы можете сделать что-то вроде этого:
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;
}
}
РЕДАКТИРОВАТЬ
Как указал JaredPar, мое предложение ниже не сработает, поскольку вы не можете применять операторы к дженерикам ...
Так что вам нужно иметь определенные реализации для каждого типа, который вы хотите сравнить / вычислить ...
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
Вы можете сделать что-то вроде этого.
Вам также нужно будет попробовать / поймать все это, чтобы убедиться, что любой T поддерживает конкретные операции.
Не возражайте, если я спрошу, зачем вам это нужно. Вы пишете какой-то математический анализатор?
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();
}
}
Нет, это невозможно, и какого черта вы хотите это сделать?
Вы могли бы , конечно, создайте такую функцию, как:
public static bool Compare<T>(char op, T a, T b);
Вам следует изучить использование деревьев выражений .NET 3.5. Вы можете вручную создавать выражения в дереве выражений (в основном в AST), а затем вызывать Expression.Compile () для создания вызываемого делегата. Вашему методу LogicRule.Test () потребуется построить дерево выражений, заключить дерево в выражение LambdaExpression, которое принимает объект, к которому вы применяете правила, в качестве аргумента, вызывает Compile () и вызывает полученный делегат.
Я сделал что-то подобное с помощью:
Этот инструмент может по существу вычислять широкий диапазон выражений. Базовое использование будет заключаться в передаче строки вроде '3> 4', и инструмент вернет false.
Однако вы также можете создать экземпляр оценщика и передать пары имя / значение объекта, и это может быть немного более интуитивно понятный IE: myObject ^ 7 На сайте codeplex есть еще тонна дополнительных функций.
<Function = "PredicateMore" Param1 = "Object1.Value" Param2 = "0"/>
Я думаю, что вы можете добиться именно этого, используя неявное приведение . Что-то вроде:
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.
Vici Parser (с открытым исходным кодом), возможно, вам поможет. Это синтаксический анализатор выражений C #, в котором вы можете просто передать строку, содержащую выражение, и получить обратно вычисленный результат.