在比较实体和聚合根时,我使用的是ABC,我是从Oren Eini借来的:Generic Entity Equality。对于价值对象,我同样聪明。我使用了Jimmy Bogard的价值对象ABC:Generic Value Object Equality
现在我的问题是;我应该支持继承这些ABCs,还是应该使用泛型equality / comparer来构建上述行为?我打算重用上面的等式实现。
我认为这回到了具有默认Equals实现的System.Object,这使得语言血腥易于使用,但也提供了有趣的窘境。 Jon Skeet在此详细介绍:Comparison methods
任何人都可以想到任何赞成或缺点吗?
总而言之,是否有人对使用实体的自定义平等实现有任何经验?我的目标是更全面地了解实施选择并实施解决方案,这将延长项目的使用寿命(减少熵)并提高可维护性。
答案 0 :(得分:0)
这并没有真正回答你的问题(对不起!),但我认为这是一个试图帮助解决你在这里遇到的一些问题的项目。我回来后写了这些东西,但从那时起就没有做过任何事情。
该项目名为Essence(http://essence.codeplex.com/),它使用System.Linq.Expression库生成(基于属性)Equals / GetHashCode / CompareTo / ToString的标准表示,以及能够根据参数列表创建IEqualityComparer和IComparer类。 (我还有一些进一步的想法,但希望在继续进一步深入之前获得一些社区反馈。)
(这意味着它几乎和手写一样快 - 主要的不是CompareTo();因为Linq.Expressions在3.5版本中没有变量的概念 - 因此,当你没有得到匹配时,你必须在底层对象上调用CompareTo()两次。使用Linq.Expressions的DLR扩展来解决这个问题。我想我可以使用emit il,但我不是那个启发当时。)
这是一个非常简单的想法,但我之前没有看到它。
现在问题是,我对抛光它感兴趣(包括为codeproject写一篇文章,记录一些代码等),但如果你觉得它可能会被说服这样做会有兴趣。
(codeplex网站没有可下载的软件包;只需转到源代码并抓住它 - 哦,它是用f#编写的(虽然所有测试代码都在c#中),因为这是我感兴趣的东西。)
无论如何,这是我的测试用例中的一些示例c#示例。
// --------------------------------------------------------------------
// 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]);
}
玩得开心!
保罗。