基本的にここに問題があります。システム内のすべてのエンティティは、タイプとid
.
new Customer() { Id = 1} == new Customer() {Id = 1};
new Customer() { Id = 1} != new Customer() {Id = 2};
new Customer() { Id = 1} != new Product() {Id = 1};
かなり標準的なシナリオ。すべてのエンティティには Id があるため、すべてのエンティティのインターフェイスを定義します。
public interface IEntity {
int Id { get; set;}
}
そして、私が作成するエンティティの作成を簡素化するために:
public abstract class BaseEntity<T> : where T : IEntity {
int Id { get; set;}
public static bool operator ==(BaseEntity<T> e1, BaseEntity<T> e2) {
if (object.ReferenceEquals(null, e1)) return false;
return e1.Equals(e2);
}
public static bool operator !=(BaseEntity<T> e1, BaseEntity<T> e2) {
return !(e1 == e2);
}
}
Customer と Product は次のようなものです
public class Customer : BaseEntity<Customer>, IEntity {}
public class Product : BaseEntity<Product>, IEntity {}
ハンキードーリーだと思います。私がしなければならないことは、各エンティティで Equals をオーバーライドすることだけだと思います (私が非常に賢い場合は、 で一度だけオーバーライドすることもできますBaseEntity
)。
だから今、私は自分のテスト範囲を拡大しており、それほど単純ではないことがわかりました! まず、ダウンキャストしてオーバーライドIEntity
を使用==
する場合は使用されません。BaseEntity<>
それで、解決策は何ですか?他にできることはありますか?そうでない場合、これは非常に面倒です。
更新 1私のテストに何か問題があるように思われます - むしろ、ジェネリックの比較に問題があります。これをチェックしてください:
[Test] public void when_created_manually_non_generic() {
// PASSES!
var e1 = new Terminal() {Id = 1};
var e2 = new Terminal() {Id = 1};
Assert.IsTrue(e1 == e2);
}
[Test] public void when_created_manually_generic() {
// FAILS!
GenericCompare(new Terminal() { Id = 1 }, new Terminal() { Id = 1 });
}
private void GenericCompare<T>(T e1, T e2) where T : class, IEntity {
Assert.IsTrue(e1 == e2);
}
何が起きてる?これは私が恐れていたほど大きな問題ではありませんが、それでも非常に厄介で、言語の動作が完全に直観的ではありません。
更新 2ああ、わかりました。ジェネリックIEntity
は何らかの理由で暗黙的にダウンキャストされます。これは直観的ではなく、ジェネリック メソッドまたはクラス内で発生するすべてのことを比較する必要があることを覚えておく必要があるため、ドメインの消費者にとって問題になる可能性があることを支持します。Equals()