Created
March 22, 2016 13:50
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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