基本上这就是问题所在。我系统中的所有实体都由它们的类型和它们的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);
}
}
客户和产品类似于
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()