Fondamentalement, voici le problème. Toutes les entités de mon système sont identifiées par leur type et leur id
.Une façon d'autoriser les classes implémentant IEntity et downcast à avoir des opérateurs == comparaisons?
new Customer() { Id = 1} == new Customer() {Id = 1};
new Customer() { Id = 1} != new Customer() {Id = 2};
new Customer() { Id = 1} != new Product() {Id = 1};
Scénario plutôt classique. Comme toutes les entités ont un identifiant, je définis une interface pour toutes les entités.
public interface IEntity {
int Id { get; set;}
}
Et pour simplifier la création d'entités je fais:
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);
}
}
où la clientèle et le produit sont quelque chose comme
public class Customer : BaseEntity<Customer>, IEntity {}
public class Product : BaseEntity<Product>, IEntity {}
Je pense que c'est Hunky Dory. Je pense que tout ce que j'ai à faire est de remplacer Equals dans chaque entité (si je suis super intelligent, je peux même le remplacer une seule fois dans le BaseEntity
) et tout le travail.
Alors maintenant, j'élargis ma couverture de test et je trouve que ce n'est pas si simple! Tout d'abord, lors du downcasting à IEntity
et en utilisant ==
le remplacement BaseEntity<>
n'est pas utilisé.
Alors, quelle est la solution? Y a-t-il autre chose que je puisse faire? Sinon, c'est vraiment ennuyeux.
Mise à jour 1 Il semblerait qu'il y ait quelque chose qui cloche avec mes tests - ou plutôt avec des comparatifs sur les génériques. Vérifiez cela:
[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);
}
Que se passe-t-il ici? Ce problème n'est pas aussi grave que je le craignais, mais il est toujours assez énervant et complètement inintéressant pour le comportement de la langue.
Mise à jour 2 Ah Je comprends, les génériques implicitement downcasts à IEntity
pour une raison quelconque. Je maintiens ceci étant non intuitif et potentiellement problématique pour les consommateurs de mon domaine car ils doivent se rappeler que tout ce qui se passe dans une méthode générique ou une classe doit être comparé avec Equals()
Est-client ou mettre en œuvre IEntity héritent de BaseEntity? Vous avez du mal à déduire la connexion entre vos exemples concrets et le code de base. –
Il fait les deux. BaseEntity <> est une classe abstraite d'aide utilisée en option pour aider à créer des entités, IEntity est ce que toute personne qui s'intéresse à autre chose que la création d'objet devrait utiliser. Le meilleur moyen que j'ai trouvé de garder mes hiérarchies flexibles tout en faisant DRY. –
Pourriez-vous ajouter dans les déclarations de classe pour le client et le produit? Cela rendrait cela plus facile à comprendre, je pense ... – CodeRedick