This doesn't really answer your question (sorry!), but I think it is a project which attempts to help with some of the questions you have here. I wrote this stuff a little while back but haven't done anything which is it since then.
The project is called Essence ( http://essence.codeplex.com/ ), and it uses the System.Linq.Expression libraries to generate (based on attributes) standard representations of Equals/GetHashCode/CompareTo/ToString, as well as being able to create IEqualityComparer and IComparer classes based on an argument list. (I also have some further ideas, but would like to get some community feedback before continuing too much further.)
(What this means is that it's almost as fast as being handwritten - the main one where it isn't is the CompareTo(); cause the Linq.Expressions doesn't have the concept of a variable in the 3.5 release - so you have to call CompareTo() on the underlying object twice when you don't get a match. Using the DLR extensions to Linq.Expressions solves this. I suppose I could have used the emit il, but I wasn't that inspired at the time.)
It's quite a simple idea, but I haven't seen it done before.
Now the thing is, I kind of lost interest in polishing it (which would have included writing an article for codeproject, documenting some of the code, or the like), but I might be persuaded to do so if you feel it would be something of interest.
(The codeplex site doesn't have a downloadable package; just go to the source and grab that - oh, it's written in f# (although all the test code is in c#) as that was the thing I was interested in learning.)
Anyway, here is are some sample c# examples from my test cases.
// --------------------------------------------------------------------
// USING MY ESSENCE LIBRARY:
// --------------------------------------------------------------------
[EssenceClass(UseIn = EssenceFunctions.All)]
public class TestEssence : IEquatable<TestEssence>, IComparable<TestEssence>
{
[Essence(Order=0, Format="i={0},")] public int MyInt { get; set; }
[Essence(Order=1, Format="s={0},")] public string MyString { get; set; }
[Essence(Order=2, Format="d={0:yyyy-MM-dd}")] public DateTime MyDateTime { get; set; }
public override int GetHashCode() { return Essence<TestEssence>.GetHashCodeStatic(this); }
public override string ToString() { return Essence<TestEssence>.ToStringStatic(this); }
public int CompareTo(TestEssence other) { return Essence<TestEssence>.CompareToStatic(this, other); }
public static bool operator ==(TestEssence lhs, TestEssence rhs) { return Essence<TestEssence>.EqualsStatic(lhs, rhs); }
public override bool Equals(object obj) { return this == (TestEssence)obj; }
public bool Equals(TestEssence other) { return this == other; }
public static bool operator !=(TestEssence lhs, TestEssence rhs) { return !(lhs == rhs); }
}
// --------------------------------------------------------------------
// EQUIVALENT HAND WRITTEN CODE:
// --------------------------------------------------------------------
public class TestManual
{
public int MyInt;
public string MyString;
public DateTime MyDateTime;
public override int GetHashCode()
{
var x = MyInt.GetHashCode();
x *= Essence<TestEssence>.HashCodeMultiplier;
x ^= (MyString == null) ? 0 : MyString.GetHashCode();
x *= Essence<TestEssence>.HashCodeMultiplier;
x ^= MyDateTime.GetHashCode();
return x;
}
public static bool operator ==(TestManual lhs, TestManual rhs)
{
if (ReferenceEquals(lhs, null))
{
if (ReferenceEquals(rhs, null))
return true;
return false;
}
if (ReferenceEquals(rhs, null))
return false;
if (ReferenceEquals(lhs, rhs))
return true;
if (typeof(TestManual) != rhs.GetType())
return false;
return lhs.MyInt == rhs.MyInt
&& lhs.MyString == rhs.MyString
&& lhs.MyDateTime == rhs.MyDateTime;
}
public override bool Equals(object obj) { return this == obj as TestManual; }
public bool Equals(TestManual other) { return this == other; }
public static bool operator !=(TestManual lhs, TestManual rhs) { return !(lhs == rhs); }
public override string ToString()
{
if (MyString == null)
return string.Format("i={0},d={1:yyyy-MM-dd}", MyInt, MyDateTime);
return string.Format("i={0},s={1},d={2:yyyy-MM-dd}", MyInt, MyString, MyDateTime);
}
public int CompareTo(TestManual other)
{
if (other == null)
return 1;
if (ReferenceEquals(this, other))
return 0;
int result = 0;
result = MyInt.CompareTo(other.MyInt);
if (result != 0) return result;
result = MyString.CompareTo(other.MyString);
if (result != 0) return result;
result = MyDateTime.CompareTo(other.MyDateTime);
if (result != 0) return result;
return result;
}
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// ALTERNATIVE USAGE
// --------------------------------------------------------------------
// --------------------------------------------------------------------
class Simple
{
public Simple(int value) { Value1 = value; }
public Simple(int value1, int value2) { Value1 = value1; Value2 = value2; }
public readonly int Value1;
public readonly int Value2;
}
[Test]
public void TestReverseForwardString()
{
var _11 = new Simple(1, 1);
var _12 = new Simple(1, 2);
var _21 = new Simple(2, 1);
var _22 = new Simple(2, 2);
var items = new[] { _11, _12, _21, _22 };
var reverseComparer = Essence<Simple>.CreateComparer("-Value1", "Value2");
Array.Sort(items, reverseComparer);
Assert.AreSame(_21, items[0]);
Assert.AreSame(_22, items[1]);
Assert.AreSame(_11, items[2]);
Assert.AreSame(_12, items[3]);
}
[Test]
public void TestReverseForwardLambda()
{
var _11 = new Simple(1, 1);
var _12 = new Simple(1, 2);
var _21 = new Simple(2, 1);
var _22 = new Simple(2, 2);
var items = new[] { _11, _12, _21, _22 };
var reverseComparer = Essence<Simple>.CreateComparer(x => x.Action.ReverseNext, x => x.Member.Value1, x => x.Member.Value2);
Array.Sort(items, reverseComparer);
Assert.AreSame(_21, items[0]);
Assert.AreSame(_22, items[1]);
Assert.AreSame(_11, items[2]);
Assert.AreSame(_12, items[3]);
}
Have fun!
Paul.