using System;
using System.Linq.Expressions;
using MiscUtil.Linq;
namespace MiscUtil
{
///
/// The Operator class provides easy access to the standard operators
/// (addition, etc) for generic types, using type inference to simplify
/// usage.
///
public static class Operator
{
///
/// Indicates if the supplied value is non-null,
/// for reference-types or Nullable<T>
///
/// True for non-null values, else false
public static bool HasValue(T value)
{
return Operator.NullOp.HasValue(value);
}
///
/// Increments the accumulator only
/// if the value is non-null. If the accumulator
/// is null, then the accumulator is given the new
/// value; otherwise the accumulator and value
/// are added.
///
/// The current total to be incremented (can be null)
/// The value to be tested and added to the accumulator
/// True if the value is non-null, else false - i.e.
/// "has the accumulator been updated?"
public static bool AddIfNotNull(ref T accumulator, T value)
{
return Operator.NullOp.AddIfNotNull(ref accumulator, value);
}
///
/// Evaluates unary negation (-) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static T Negate(T value)
{
return Operator.Negate(value);
}
///
/// Evaluates bitwise not (~) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static T Not(T value)
{
return Operator.Not(value);
}
///
/// Evaluates bitwise or (|) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static T Or(T value1, T value2)
{
return Operator.Or(value1, value2);
}
///
/// Evaluates bitwise and (&) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static T And(T value1, T value2)
{
return Operator.And(value1, value2);
}
///
/// Evaluates bitwise xor (^) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static T Xor(T value1, T value2)
{
return Operator.Xor(value1, value2);
}
///
/// Performs a conversion between the given types; this will throw
/// an InvalidOperationException if the type T does not provide a suitable cast, or for
/// Nullable<TInner> if TInner does not provide this cast.
///
public static TTo Convert(TFrom value)
{
return Operator.Convert(value);
}
///
/// Evaluates binary addition (+) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static T Add(T value1, T value2)
{
return Operator.Add(value1, value2);
}
///
/// Evaluates binary addition (+) for the given type(s); this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static TArg1 AddAlternative(TArg1 value1, TArg2 value2)
{
return Operator.Add(value1, value2);
}
///
/// Evaluates binary subtraction (-) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static T Subtract(T value1, T value2)
{
return Operator.Subtract(value1, value2);
}
///
/// Evaluates binary subtraction(-) for the given type(s); this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static TArg1 SubtractAlternative(TArg1 value1, TArg2 value2)
{
return Operator.Subtract(value1, value2);
}
///
/// Evaluates binary multiplication (*) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static T Multiply(T value1, T value2)
{
return Operator.Multiply(value1, value2);
}
///
/// Evaluates binary multiplication (*) for the given type(s); this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static TArg1 MultiplyAlternative(TArg1 value1, TArg2 value2)
{
return Operator.Multiply(value1, value2);
}
///
/// Evaluates binary division (/) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static T Divide(T value1, T value2)
{
return Operator.Divide(value1, value2);
}
///
/// Evaluates binary division (/) for the given type(s); this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static TArg1 DivideAlternative(TArg1 value1, TArg2 value2)
{
return Operator.Divide(value1, value2);
}
///
/// Evaluates binary equality (==) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static bool Equal(T value1, T value2)
{
return Operator.Equal(value1, value2);
}
///
/// Evaluates binary inequality (!=) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static bool NotEqual(T value1, T value2)
{
return Operator.NotEqual(value1, value2);
}
///
/// Evaluates binary greater-than (>) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static bool GreaterThan(T value1, T value2)
{
return Operator.GreaterThan(value1, value2);
}
///
/// Evaluates binary less-than (<) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static bool LessThan(T value1, T value2)
{
return Operator.LessThan(value1, value2);
}
///
/// Evaluates binary greater-than-on-eqauls (>=) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static bool GreaterThanOrEqual(T value1, T value2)
{
return Operator.GreaterThanOrEqual(value1, value2);
}
///
/// Evaluates binary less-than-or-equal (<=) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static bool LessThanOrEqual(T value1, T value2)
{
return Operator.LessThanOrEqual(value1, value2);
}
///
/// Evaluates integer division (/) for the given type; this will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
/// This operation is particularly useful for computing averages and
/// similar aggregates.
///
public static T DivideInt32(T value, int divisor)
{
return Operator.Divide(value, divisor);
}
}
///
/// Provides standard operators (such as addition) that operate over operands of
/// different types. For operators, the return type is assumed to match the first
/// operand.
///
///
///
public static class Operator
{
private static readonly Func convert;
///
/// Returns a delegate to convert a value between two types; this delegate will throw
/// an InvalidOperationException if the type T does not provide a suitable cast, or for
/// Nullable<TInner> if TInner does not provide this cast.
///
public static Func Convert { get { return convert; } }
static Operator()
{
convert = ExpressionUtil.CreateExpression(body => Expression.Convert(body, typeof(TResult)));
add = ExpressionUtil.CreateExpression(Expression.Add, true);
subtract = ExpressionUtil.CreateExpression(Expression.Subtract, true);
multiply = ExpressionUtil.CreateExpression(Expression.Multiply, true);
divide = ExpressionUtil.CreateExpression(Expression.Divide, true);
}
private static readonly Func add, subtract, multiply, divide;
///
/// Returns a delegate to evaluate binary addition (+) for the given types; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Add { get { return add; } }
///
/// Returns a delegate to evaluate binary subtraction (-) for the given types; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Subtract { get { return subtract; } }
///
/// Returns a delegate to evaluate binary multiplication (*) for the given types; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Multiply { get { return multiply; } }
///
/// Returns a delegate to evaluate binary division (/) for the given types; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Divide { get { return divide; } }
}
///
/// Provides standard operators (such as addition) over a single type
///
///
///
public static class Operator
{
static readonly INullOp nullOp;
internal static INullOp NullOp { get { return nullOp; } }
static readonly T zero;
///
/// Returns the zero value for value-types (even full Nullable<TInner>) - or null for reference types
///
public static T Zero { get { return zero;} }
static readonly Func negate, not;
static readonly Func or, and, xor;
///
/// Returns a delegate to evaluate unary negation (-) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Negate { get { return negate; } }
///
/// Returns a delegate to evaluate bitwise not (~) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Not { get { return not; } }
///
/// Returns a delegate to evaluate bitwise or (|) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Or { get { return or; } }
///
/// Returns a delegate to evaluate bitwise and (&) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func And { get { return and; } }
///
/// Returns a delegate to evaluate bitwise xor (^) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Xor { get { return xor; } }
static readonly Func add, subtract, multiply, divide;
///
/// Returns a delegate to evaluate binary addition (+) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Add { get { return add; } }
///
/// Returns a delegate to evaluate binary subtraction (-) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Subtract { get { return subtract; } }
///
/// Returns a delegate to evaluate binary multiplication (*) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Multiply { get { return multiply; } }
///
/// Returns a delegate to evaluate binary division (/) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Divide { get { return divide; } }
static readonly Func equal, notEqual, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual;
///
/// Returns a delegate to evaluate binary equality (==) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Equal { get { return equal; } }
///
/// Returns a delegate to evaluate binary inequality (!=) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func NotEqual { get { return notEqual; } }
///
/// Returns a delegate to evaluate binary greater-then (>) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func GreaterThan { get { return greaterThan; } }
///
/// Returns a delegate to evaluate binary less-than (<) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func LessThan { get { return lessThan; } }
///
/// Returns a delegate to evaluate binary greater-than-or-equal (>=) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func GreaterThanOrEqual { get { return greaterThanOrEqual; } }
///
/// Returns a delegate to evaluate binary less-than-or-equal (<=) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func LessThanOrEqual { get { return lessThanOrEqual; } }
static Operator()
{
add = ExpressionUtil.CreateExpression(Expression.Add);
subtract = ExpressionUtil.CreateExpression(Expression.Subtract);
divide = ExpressionUtil.CreateExpression(Expression.Divide);
multiply = ExpressionUtil.CreateExpression(Expression.Multiply);
greaterThan = ExpressionUtil.CreateExpression(Expression.GreaterThan);
greaterThanOrEqual = ExpressionUtil.CreateExpression(Expression.GreaterThanOrEqual);
lessThan = ExpressionUtil.CreateExpression(Expression.LessThan);
lessThanOrEqual = ExpressionUtil.CreateExpression(Expression.LessThanOrEqual);
equal = ExpressionUtil.CreateExpression(Expression.Equal);
notEqual = ExpressionUtil.CreateExpression(Expression.NotEqual);
negate = ExpressionUtil.CreateExpression(Expression.Negate);
and = ExpressionUtil.CreateExpression(Expression.And);
or = ExpressionUtil.CreateExpression(Expression.Or);
not = ExpressionUtil.CreateExpression(Expression.Not);
xor = ExpressionUtil.CreateExpression(Expression.ExclusiveOr);
Type typeT = typeof(T);
if(typeT.IsValueType && typeT.IsGenericType && (typeT.GetGenericTypeDefinition() == typeof(Nullable<>))) {
// get the *inner* zero (not a null Nullable, but default(TValue))
Type nullType = typeT.GetGenericArguments()[0];
zero = (T)Activator.CreateInstance(nullType);
nullOp = (INullOp)Activator.CreateInstance(
typeof(StructNullOp<>).MakeGenericType(nullType));
} else {
zero = default(T);
if (typeT.IsValueType)
{
nullOp = (INullOp)Activator.CreateInstance(
typeof(StructNullOp<>).MakeGenericType(typeT));
}
else
{
nullOp = (INullOp)Activator.CreateInstance(
typeof(ClassNullOp<>).MakeGenericType(typeT));
}
}
}
}
}