Skip to content

Instantly share code, notes, and snippets.

@RoadieRich
Created March 22, 2016 13:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RoadieRich/8ffbf6ac08fedd39c528 to your computer and use it in GitHub Desktop.
Save RoadieRich/8ffbf6ac08fedd39c528 to your computer and use it in GitHub Desktop.
AsComparable, A wrapper around objects implementing IComparable, to allow use of comparison operators (<, >, != etc)
public sealed class Comparable<T> : IComparable<Comparable<T>>, IComparable<T>, IEquatable<Comparable<T>>,
IEquatable<T> where T : IComparable<T>
{
/// <summary>
/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
/// </summary>
/// <returns>
/// true if the specified object is equal to the current object; otherwise, false.
/// </returns>
/// <param name="obj">The object to compare with the current object. </param>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (ReferenceEquals(Value, obj)) return true;
if (obj.GetType() == GetType()) return Comparer<T>.Default.Compare(Value, ((Comparable<T>)obj).Value) == 0;
if (obj.GetType() == Value.GetType()) return Comparer<T>.Default.Compare(Value, (T)obj) == 0;
return false;
}
private T Value { get; set; }
public static bool operator <(Comparable<T> left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left.Value, right.Value) < 0;
}
public static bool operator >(Comparable<T> left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left.Value, right.Value) > 0;
}
public static bool operator <=(Comparable<T> left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left.Value, right.Value) <= 0;
}
public static bool operator >=(Comparable<T> left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left.Value, right.Value) >= 0;
}
public static bool operator ==(Comparable<T> left, Comparable<T> right)
{
return ReferenceEquals(left, right) ||
!ReferenceEquals(right, null) &&
!ReferenceEquals(left, null) &&
Comparer<T>.Default.Compare(left.Value, right.Value) == 0;
}
public static bool operator !=(Comparable<T> left, Comparable<T> right)
{
return !(left == right);
}
public static bool operator <(Comparable<T> left, T right)
{
return Comparer<T>.Default.Compare(left.Value, right) < 0;
}
public static bool operator >(Comparable<T> left, T right)
{
return Comparer<T>.Default.Compare(left.Value, right) > 0;
}
public static bool operator <=(Comparable<T> left, T right)
{
return Comparer<T>.Default.Compare(left.Value, right) <= 0;
}
public static bool operator >=(Comparable<T> left, T right)
{
return Comparer<T>.Default.Compare(left.Value, right) >= 0;
}
public static bool operator ==(Comparable<T> left, T right)
{
return left != null && Comparer<T>.Default.Compare(left.Value, right) == 0;
}
public static bool operator !=(Comparable<T> left, T right)
{
return left != null && Comparer<T>.Default.Compare(left.Value, right) != 0;
}
public static bool operator <(T left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left, right.Value) < 0;
}
public static bool operator >(T left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left, right.Value) > 0;
}
public static bool operator <=(T left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left, right.Value) <= 0;
}
public static bool operator >=(T left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left, right.Value) >= 0;
}
public static bool operator ==(T left, Comparable<T> right)
{
return right != null && Comparer<T>.Default.Compare(left, right.Value) == 0;
}
public static bool operator !=(T left, Comparable<T> right)
{
return right != null && Comparer<T>.Default.Compare(left, right.Value) != 0;
}
public static implicit operator T(Comparable<T> comparable)
{
return comparable.Value;
}
public static implicit operator Comparable<T>(T value)
{
return new Comparable<T> { Value = value };
}
/// <summary>
/// Compares the current object with another object of the same type.
/// </summary>
/// <returns>
/// A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
/// </returns>
/// <param name="other">An object to compare with this object.</param>
int IComparable<T>.CompareTo(T other)
{
return Comparer<T>.Default.Compare(Value, other);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
/// <param name="other">An object to compare with this object.</param>
bool IEquatable<Comparable<T>>.Equals(Comparable<T> other)
{
return Comparer<T>.Default.Compare(Value, other.Value) == 0;
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
/// <param name="other">An object to compare with this object.</param>
bool IEquatable<T>.Equals(T other)
{
return Comparer<T>.Default.Compare(Value, other) == 0;
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
/// <returns>
/// A hash code for the current <see cref="T:System.Object"/>.
/// </returns>
public override int GetHashCode()
{
return Value.GetHashCode();
}
int IComparable<Comparable<T>>.CompareTo(Comparable<T> other)
{
return Value.CompareTo(other.Value);
}
internal static Comparable<T> New(T value)
{
return new Comparable<T> { Value = value };
}
}
[PublicAPI]
public static class Comparable
{
[PublicAPI]
public static Comparable<T> AsComparable<T>(this T value) where T : IComparable<T>
{
return Comparable<T>.New(value);
}
[PublicAPI]
public static Comparable<T> AsComparable<T>(this Comparable<T> value) where T : IComparable<T>
{
return value;
}
[PublicAPI]
public static RightComparable<T1, T2> AsRightComparable<T1, T2>(this T1 value) where T2 : IComparable<T1>
{
return RightComparable<T1, T2>.New<T1, T2>(value);
}
[PublicAPI]
public static RightComparable<T1, T2> AsRightComparable<T1, T2>(this RightComparable<T1, T2> value)
where T2 : IComparable<T1>
{
return value;
}
[PublicAPI]
public static LeftComparable<T1, T2> AsLeftComparable<T1, T2>(this T1 value) where T1 : IComparable<T2>
{
return LeftComparable<T1, T2>.New<T1, T2>(value);
}
[PublicAPI]
public static LeftComparable<T1, T2> AsLeftComparable<T1, T2>(this LeftComparable<T1, T2> value)
where T1 : IComparable<T2>
{
return value;
}
public static BaseComparable<TLeft, TRight> AsComparableFor<TLeft, TRight>(this TLeft left, TRight right)
{
if (left is IComparable<TRight>)
{
var constructor =
typeof(LeftComparable<,>).MakeGenericType(typeof(TLeft), typeof(TRight))
.GetConstructor(new[] { typeof(TLeft) });
if (constructor != null)
{
return (BaseComparable<TLeft, TRight>)constructor.Invoke(new object[] { left });
}
}
if (right is IComparable<TLeft>)
{
var constructor =
typeof(RightComparable<,>).MakeGenericType(typeof(TLeft), typeof(TRight))
.GetConstructor(new[] { typeof(TLeft) });
if (constructor != null)
{
return (BaseComparable<TLeft, TRight>)constructor.Invoke(new object[] { left });
}
}
throw new ArgumentException();
}
[PublicAPI]
public static Comparable<T> Max<T>(T a, T b) where T : IComparable<T>
{
var aComparable = a.AsComparable();
var bComparable = b.AsComparable();
return aComparable >= bComparable
? aComparable
: bComparable;
}
[PublicAPI]
public static Comparable<T> Min<T>(T a, T b) where T : IComparable<T>
{
var aComparable = a.AsComparable();
var bComparable = b.AsComparable();
return aComparable <= bComparable
? aComparable
: bComparable;
}
[PublicAPI]
public static Comparable<T> Max<T>(Comparable<T> a, T b) where T : IComparable<T>
{
return a >= b
? a
: b.AsComparable();
}
[PublicAPI]
public static Comparable<T> Min<T>(Comparable<T> a, T b) where T : IComparable<T>
{
return a <= b
? a
: b.AsComparable();
}
[PublicAPI]
public static Comparable<T> Max<T>(Comparable<T> a, Comparable<T> b) where T : IComparable<T>
{
return a >= b
? a
: b;
}
[PublicAPI]
public static Comparable<T> Min<T>(Comparable<T> a, Comparable<T> b) where T : IComparable<T>
{
return a <= b
? a
: b;
}
[PublicAPI]
public static Comparable<T> Max<T>(T a, Comparable<T> b) where T : IComparable<T>
{
return a >= b
? a.AsComparable()
: b;
}
[PublicAPI]
public static Comparable<T> Min<T>(T a, Comparable<T> b) where T : IComparable<T>
{
return a <= b
? a.AsComparable()
: b;
}
}
public abstract class BaseComparable<TLeft, TRight> : IComparable<TRight>, IEquatable<TRight>
{
protected bool Equals(BaseComparable<TLeft, TRight> other)
{
return EqualityComparer<TLeft>.Default.Equals(Value, other.Value);
}
protected bool Equals(TLeft other)
{
return EqualityComparer<TLeft>.Default.Equals(Value, other);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
/// <param name="other">An object to compare with this object.</param>
public bool Equals(TRight other)
{
return CompareTo(other) == 0;
}
/// <summary>
/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
/// </summary>
/// <returns>
/// true if the specified object is equal to the current object; otherwise, false.
/// </returns>
/// <param name="obj">The object to compare with the current object. </param>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() == this.GetType())
return Equals((BaseComparable<TLeft, TRight>)obj);
if (obj.GetType() == Value.GetType())
return Equals((TLeft)obj);
return false;
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
/// <returns>
/// A hash code for the current <see cref="T:System.Object"/>.
/// </returns>
public override int GetHashCode()
{
return EqualityComparer<TLeft>.Default.GetHashCode(Value);
}
public BaseComparable(TLeft left)
{
Value = left;
}
public TLeft Value { get; set; }
public abstract int CompareTo(TRight right);
public static bool operator >(BaseComparable<TLeft, TRight> left, TRight right)
{
return left.CompareTo(right) > 0;
}
public static bool operator <(BaseComparable<TLeft, TRight> left, TRight right)
{
return left.CompareTo(right) < 0;
}
public static bool operator >(TRight left, BaseComparable<TLeft, TRight> right)
{
return right.CompareTo(left) < 0;
}
public static bool operator <(TRight left, BaseComparable<TLeft, TRight> right)
{
return right.CompareTo(left) > 0;
}
public static bool operator >=(BaseComparable<TLeft, TRight> left, TRight right)
{
return left.CompareTo(right) >= 0;
}
public static bool operator <=(BaseComparable<TLeft, TRight> left, TRight right)
{
return left.CompareTo(right) <= 0;
}
public static bool operator >=(TRight left, BaseComparable<TLeft, TRight> right)
{
return right.CompareTo(left) <= 0;
}
public static bool operator <=(TRight left, BaseComparable<TLeft, TRight> right)
{
return right.CompareTo(left) >= 0;
}
public static bool operator ==(BaseComparable<TLeft, TRight> left, TRight right)
{
return left != null && left.CompareTo(right) == 0;
}
public static bool operator !=(BaseComparable<TLeft, TRight> left, TRight right)
{
return left != null && left.CompareTo(right) != 0;
}
public static bool operator ==(TRight left, BaseComparable<TLeft, TRight> right)
{
return right != null && right.CompareTo(left) == 0;
}
public static bool operator !=(TRight left, BaseComparable<TLeft, TRight> right)
{
return right != null && right.CompareTo(left) != 0;
}
}
public sealed class LeftComparable<TLeft, TRight> : BaseComparable<TLeft, TRight>
where TLeft : IComparable<TRight>
{
public LeftComparable(TLeft left) : base(left) { }
/// <summary>
/// Compares the current object with another object of the same type.
/// </summary>
/// <returns>
/// A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
/// </returns>
/// <param name="other">An object to compare with this object.</param>
public override int CompareTo(TRight right)
{
return Value.CompareTo(right);
}
public static LeftComparable<T1, T2> New<T1, T2>(T1 value) where T1 : IComparable<T2>
{
return new LeftComparable<T1, T2>(value);
}
}
public sealed class RightComparable<TLeft, TRight> : BaseComparable<TLeft, TRight>
where TRight : IComparable<TLeft>
{
public RightComparable(TLeft left) : base(left) { }
/// <summary>
/// Compares the current object with another object of the same type.
/// </summary>
/// <returns>
/// A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
/// </returns>
/// <param name="right">An object to compare with this object.</param>
public override int CompareTo(TRight right)
{
return -right.CompareTo(Value);
}
public static RightComparable<T1, T2> New<T1, T2>(T1 value)
where T2 : IComparable<T1>
{
return new RightComparable<T1, T2>(value);
}
}
<Query Kind="Program">
<Connection>
<ID>a72a555a-9eff-4419-97c7-761fdf9019cc</ID>
<Persist>true</Persist>
<Server>G7799\SQLEXPRESS</Server>
<Database>GridInv</Database>
<ShowServer>true</ShowServer>
</Connection>
<Namespace>System</Namespace>
<Namespace>System.Collections.Generic</Namespace>
<Namespace>System.Reflection</Namespace>
</Query>
void Main()
{
var foo1 = new Foo { Bar = 1 };
var foo2 = new Foo { Bar = 2 };
var foo3 = new Foo { Bar = 2 };
//(foo1 < foo2).Dump(); // does not compile
(foo1.AsComparable() < foo2).Dump("foo1.AsComparable() < foo2"); // does compile
(foo2 == foo3).Dump("foo2 == foo3"); //false
(foo2.AsComparable() == foo3).Dump("foo2.AsComparable() == foo3"); //true
var bar = new Bar { Value = 1 };
var baz = new Baz { Value = 1 };
var baz2 = new Baz { Value = -1 };
//(bar == baz).Dump(); //Doesn't compile
var compBaz2 = baz2.AsComparableFor(bar);
var compBar = bar.AsComparableFor(baz);
bar.Value.Dump("bar");
baz2.Value.Dump("baz2");
"".Dump("LeftComparable <> basic");
(compBar < baz2).Dump("1 < -1");
(compBar > baz2).Dump("1 > -1");
(compBar <= baz2).Dump("1 <= -1");
(compBar >= baz2).Dump("1 >= -1");
(compBar == baz2).Dump("1 == -1");
(compBar != baz2).Dump("1 != -1");
"".Dump("basic <> LeftComparable");
(baz2 < compBar).Dump("-1 < 1");
(baz2 > compBar).Dump("-1 > 1");
(baz2 <= compBar).Dump("-1 <= 1");
(baz2 >= compBar).Dump("-1 >= 1");
(baz2 == compBar).Dump("-1 == 1");
(baz2 != compBar).Dump("-1 != 1");
"".Dump("basic <> RightComparable");
(bar < compBaz2).Dump("1 < -1");
(bar > compBaz2).Dump("1 > -1");
(bar <= compBaz2).Dump("1 <= -1");
(bar >= compBaz2).Dump("1 >= -1");
(bar == compBaz2).Dump("1 == -1");
(bar != compBaz2).Dump("1 != -1");
"".Dump("RightComparable <> basic");
(compBaz2 < bar).Dump("-1 < 1");
(compBaz2 > bar).Dump("-1 > 1");
(compBaz2 <= bar).Dump("-1 <= 1");
(compBaz2 >= bar).Dump("-1 >= 1");
(compBaz2 == bar).Dump("-1 == 1");
(compBaz2 != bar).Dump("-1 != 1");
}
// Define other methods and classes here
class Foo : IEquatable<Foo>, IComparable<Foo>
{
public int Bar { get; set; }
bool IEquatable<Foo>.Equals(Foo other) => this.Bar == other.Bar;
int IComparable<Foo>.CompareTo(Foo other) => this.Bar.CompareTo(other.Bar);
}
class Baz
{
public int Value { get; set; }
}
class Bar : IComparable<Baz>
{
public int Value { get; set; }
int IComparable<Baz>.CompareTo(Baz other)
{
return Value.CompareTo(other.Value);
}
}
int Compare<T1, T2>(T1 left, T2 right)
{
return (left as IComparable<T2>)?.CompareTo(right) ?? -(right as IComparable<T1>).CompareTo(left);
}
public sealed class Comparable<T> : IComparable<Comparable<T>>, IComparable<T>, IEquatable<Comparable<T>>,
IEquatable<T> where T : IComparable<T>
{
/// <summary>
/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
/// </summary>
/// <returns>
/// true if the specified object is equal to the current object; otherwise, false.
/// </returns>
/// <param name="obj">The object to compare with the current object. </param>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (ReferenceEquals(Value, obj)) return true;
if (obj.GetType() == GetType()) return Comparer<T>.Default.Compare(Value, ((Comparable<T>)obj).Value) == 0;
if (obj.GetType() == Value.GetType()) return Comparer<T>.Default.Compare(Value, (T)obj) == 0;
return false;
}
private T Value { get; set; }
public static bool operator <(Comparable<T> left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left.Value, right.Value) < 0;
}
public static bool operator >(Comparable<T> left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left.Value, right.Value) > 0;
}
public static bool operator <=(Comparable<T> left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left.Value, right.Value) <= 0;
}
public static bool operator >=(Comparable<T> left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left.Value, right.Value) >= 0;
}
public static bool operator ==(Comparable<T> left, Comparable<T> right)
{
return ReferenceEquals(left, right) ||
!ReferenceEquals(right, null) &&
!ReferenceEquals(left, null) &&
Comparer<T>.Default.Compare(left.Value, right.Value) == 0;
}
public static bool operator !=(Comparable<T> left, Comparable<T> right)
{
return !(left == right);
}
public static bool operator <(Comparable<T> left, T right)
{
return Comparer<T>.Default.Compare(left.Value, right) < 0;
}
public static bool operator >(Comparable<T> left, T right)
{
return Comparer<T>.Default.Compare(left.Value, right) > 0;
}
public static bool operator <=(Comparable<T> left, T right)
{
return Comparer<T>.Default.Compare(left.Value, right) <= 0;
}
public static bool operator >=(Comparable<T> left, T right)
{
return Comparer<T>.Default.Compare(left.Value, right) >= 0;
}
public static bool operator ==(Comparable<T> left, T right)
{
return left != null && Comparer<T>.Default.Compare(left.Value, right) == 0;
}
public static bool operator !=(Comparable<T> left, T right)
{
return left != null && Comparer<T>.Default.Compare(left.Value, right) != 0;
}
public static bool operator <(T left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left, right.Value) < 0;
}
public static bool operator >(T left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left, right.Value) > 0;
}
public static bool operator <=(T left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left, right.Value) <= 0;
}
public static bool operator >=(T left, Comparable<T> right)
{
return Comparer<T>.Default.Compare(left, right.Value) >= 0;
}
public static bool operator ==(T left, Comparable<T> right)
{
return right != null && Comparer<T>.Default.Compare(left, right.Value) == 0;
}
public static bool operator !=(T left, Comparable<T> right)
{
return right != null && Comparer<T>.Default.Compare(left, right.Value) != 0;
}
public static implicit operator T(Comparable<T> comparable)
{
return comparable.Value;
}
public static implicit operator Comparable<T>(T value)
{
return new Comparable<T> { Value = value };
}
/// <summary>
/// Compares the current object with another object of the same type.
/// </summary>
/// <returns>
/// A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
/// </returns>
/// <param name="other">An object to compare with this object.</param>
int IComparable<T>.CompareTo(T other)
{
return Comparer<T>.Default.Compare(Value, other);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
/// <param name="other">An object to compare with this object.</param>
bool IEquatable<Comparable<T>>.Equals(Comparable<T> other)
{
return Comparer<T>.Default.Compare(Value, other.Value) == 0;
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
/// <param name="other">An object to compare with this object.</param>
bool IEquatable<T>.Equals(T other)
{
return Comparer<T>.Default.Compare(Value, other) == 0;
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
/// <returns>
/// A hash code for the current <see cref="T:System.Object"/>.
/// </returns>
public override int GetHashCode()
{
return Value.GetHashCode();
}
int IComparable<Comparable<T>>.CompareTo(Comparable<T> other)
{
return Value.CompareTo(other.Value);
}
internal static Comparable<T> New(T value)
{
return new Comparable<T> { Value = value };
}
}
[PublicAPI]
public static class Comparable
{
[PublicAPI]
public static Comparable<T> AsComparable<T>(this T value) where T : IComparable<T>
{
return Comparable<T>.New(value);
}
[PublicAPI]
public static Comparable<T> AsComparable<T>(this Comparable<T> value) where T : IComparable<T>
{
return value;
}
[PublicAPI]
public static RightComparable<T1, T2> AsRightComparable<T1, T2>(this T1 value) where T2 : IComparable<T1>
{
return RightComparable<T1, T2>.New<T1, T2>(value);
}
[PublicAPI]
public static RightComparable<T1, T2> AsRightComparable<T1, T2>(this RightComparable<T1, T2> value)
where T2 : IComparable<T1>
{
return value;
}
[PublicAPI]
public static LeftComparable<T1, T2> AsLeftComparable<T1, T2>(this T1 value) where T1 : IComparable<T2>
{
return LeftComparable<T1, T2>.New<T1, T2>(value);
}
[PublicAPI]
public static LeftComparable<T1, T2> AsLeftComparable<T1, T2>(this LeftComparable<T1, T2> value)
where T1 : IComparable<T2>
{
return value;
}
public static BaseComparable<TLeft, TRight> AsComparableFor<TLeft, TRight>(this TLeft left, TRight right)
{
if (left is IComparable<TRight>)
{
var constructor =
typeof(LeftComparable<,>).MakeGenericType(typeof(TLeft), typeof(TRight))
.GetConstructor(new[] { typeof(TLeft) });
if (constructor != null)
{
return (BaseComparable<TLeft, TRight>)constructor.Invoke(new object[] { left });
}
}
if (right is IComparable<TLeft>)
{
var constructor =
typeof(RightComparable<,>).MakeGenericType(typeof(TLeft), typeof(TRight))
.GetConstructor(new[] { typeof(TLeft) });
if (constructor != null)
{
return (BaseComparable<TLeft, TRight>)constructor.Invoke(new object[] { left });
}
}
throw new ArgumentException();
}
[PublicAPI]
public static Comparable<T> Max<T>(T a, T b) where T : IComparable<T>
{
var aComparable = a.AsComparable();
var bComparable = b.AsComparable();
return aComparable >= bComparable
? aComparable
: bComparable;
}
[PublicAPI]
public static Comparable<T> Min<T>(T a, T b) where T : IComparable<T>
{
var aComparable = a.AsComparable();
var bComparable = b.AsComparable();
return aComparable <= bComparable
? aComparable
: bComparable;
}
[PublicAPI]
public static Comparable<T> Max<T>(Comparable<T> a, T b) where T : IComparable<T>
{
return a >= b
? a
: b.AsComparable();
}
[PublicAPI]
public static Comparable<T> Min<T>(Comparable<T> a, T b) where T : IComparable<T>
{
return a <= b
? a
: b.AsComparable();
}
[PublicAPI]
public static Comparable<T> Max<T>(Comparable<T> a, Comparable<T> b) where T : IComparable<T>
{
return a >= b
? a
: b;
}
[PublicAPI]
public static Comparable<T> Min<T>(Comparable<T> a, Comparable<T> b) where T : IComparable<T>
{
return a <= b
? a
: b;
}
[PublicAPI]
public static Comparable<T> Max<T>(T a, Comparable<T> b) where T : IComparable<T>
{
return a >= b
? a.AsComparable()
: b;
}
[PublicAPI]
public static Comparable<T> Min<T>(T a, Comparable<T> b) where T : IComparable<T>
{
return a <= b
? a.AsComparable()
: b;
}
}
public abstract class BaseComparable<TLeft, TRight> : IComparable<TRight>, IEquatable<TRight>
{
protected bool Equals(BaseComparable<TLeft, TRight> other)
{
return EqualityComparer<TLeft>.Default.Equals(Value, other.Value);
}
protected bool Equals(TLeft other)
{
return EqualityComparer<TLeft>.Default.Equals(Value, other);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
/// <param name="other">An object to compare with this object.</param>
public bool Equals(TRight other)
{
return CompareTo(other) == 0;
}
/// <summary>
/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
/// </summary>
/// <returns>
/// true if the specified object is equal to the current object; otherwise, false.
/// </returns>
/// <param name="obj">The object to compare with the current object. </param>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() == this.GetType())
return Equals((BaseComparable<TLeft, TRight>)obj);
if (obj.GetType() == Value.GetType())
return Equals((TLeft)obj);
return false;
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
/// <returns>
/// A hash code for the current <see cref="T:System.Object"/>.
/// </returns>
public override int GetHashCode()
{
return EqualityComparer<TLeft>.Default.GetHashCode(Value);
}
public BaseComparable(TLeft left)
{
Value = left;
}
public TLeft Value { get; set; }
public abstract int CompareTo(TRight right);
public static bool operator >(BaseComparable<TLeft, TRight> left, TRight right)
{
return left.CompareTo(right) > 0;
}
public static bool operator <(BaseComparable<TLeft, TRight> left, TRight right)
{
return left.CompareTo(right) < 0;
}
public static bool operator >(TRight left, BaseComparable<TLeft, TRight> right)
{
return right.CompareTo(left) < 0;
}
public static bool operator <(TRight left, BaseComparable<TLeft, TRight> right)
{
return right.CompareTo(left) > 0;
}
public static bool operator >=(BaseComparable<TLeft, TRight> left, TRight right)
{
return left.CompareTo(right) >= 0;
}
public static bool operator <=(BaseComparable<TLeft, TRight> left, TRight right)
{
return left.CompareTo(right) <= 0;
}
public static bool operator >=(TRight left, BaseComparable<TLeft, TRight> right)
{
return right.CompareTo(left) <= 0;
}
public static bool operator <=(TRight left, BaseComparable<TLeft, TRight> right)
{
return right.CompareTo(left) >= 0;
}
public static bool operator ==(BaseComparable<TLeft, TRight> left, TRight right)
{
return left != null && left.CompareTo(right) == 0;
}
public static bool operator !=(BaseComparable<TLeft, TRight> left, TRight right)
{
return left != null && left.CompareTo(right) != 0;
}
public static bool operator ==(TRight left, BaseComparable<TLeft, TRight> right)
{
return right != null && right.CompareTo(left) == 0;
}
public static bool operator !=(TRight left, BaseComparable<TLeft, TRight> right)
{
return right != null && right.CompareTo(left) != 0;
}
}
public sealed class LeftComparable<TLeft, TRight> : BaseComparable<TLeft, TRight>
where TLeft : IComparable<TRight>
{
public LeftComparable(TLeft left) : base(left) { }
/// <summary>
/// Compares the current object with another object of the same type.
/// </summary>
/// <returns>
/// A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
/// </returns>
/// <param name="other">An object to compare with this object.</param>
public override int CompareTo(TRight right)
{
return Value.CompareTo(right);
}
public static LeftComparable<T1, T2> New<T1, T2>(T1 value) where T1 : IComparable<T2>
{
return new LeftComparable<T1, T2>(value);
}
}
public sealed class RightComparable<TLeft, TRight> : BaseComparable<TLeft, TRight>
where TRight : IComparable<TLeft>
{
public RightComparable(TLeft left) : base(left) { }
/// <summary>
/// Compares the current object with another object of the same type.
/// </summary>
/// <returns>
/// A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
/// </returns>
/// <param name="right">An object to compare with this object.</param>
public override int CompareTo(TRight right)
{
return -right.CompareTo(Value);
}
public static RightComparable<T1, T2> New<T1, T2>(T1 value)
where T2 : IComparable<T1>
{
return new RightComparable<T1, T2>(value);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment