2017-10-18 4 views
0

J'ai donc une solution de travail pour cela, mais je ne suis pas sûr si je complique les choses.Comment définir une interface qui assure que les enfants et le parent sont du même type que l'interface définie

Disons que nous avons les deux interfaces suivantes:

public interface IPrototype 
{ 
    Guid Id { get; set; } 
    string Name { get; set; } 
} 

public interface IHierarchicalPrototype : IPrototype 
{ 
    IHierarchicalPrototype Parent { get; set; } 
    IList<IHierarchicalPrototype> Children { get; set; } 
} 

Supposons maintenant que de nombreuses implémentations de IHierarchicalPrototype existe, par exemple IEntityPrototype ou IFieldPrototype.

Dans la définition ci-dessus la Parent pourrait être une IHierarchicalPrototype et une liste d » ChildrenIEntityPrototype pourrait contenir tout IHierarchicalPrototype.

Ce que je voulais vous assurer de bien est qu'un IHierarchicalPrototype ne peut contenir des enfants de son propre type. Ainsi, un IEntityPrototype « s Children est de type IList<IEntityPrototype> et le Parent est de type IEntityPrototype.

Une solution serait de mettre en œuvre Children et Parent pour chaque prototype qui dérive de IHierarchicalPrototype mais il doit y avoir un moyen plus facile!

Ce que je suis venu avec est une solution avec les génériques.

Au lieu de définir

interface IEntityPrototype : IHierarchicalPrototype {} 

je pourrais le définir avec les génériques comme ceci:

interface IEntityPrototype : IHierarchicalPrototype<IEntityPrototype> 

Je ne peux pas me débarrasser du paramètre de type générique redondant bien. Je veux que le paramètre de type générique pour correspondre toujours l'interface que je suis en train de définir et serait en fait besoin que l'ci-dessus si je voulais des prototypes de mix comme celui-ci (que je ne)

// this will never happen! 
interface IEntityPrototype : IHierarchicalPrototype<IFieldPrototype> 

Ici aussi la définition générique de l'interface IHierarchicalPrototype

public interface IHierarchicalPrototype<THierarchical> : IPrototype 
    where THierarchical : IHierarchicalPrototype<THierarchical> 
{ 
    IHierarchicalPrototype<THierarchical> Parent { get; } 
    IList<IHierarchicalPrototype<THierarchical>> Children { get; } 
} 

Toute alternative ou des solutions plus élégantes que vous pouvez trouver?

+2

Vous pouvez lire [plus curieux] Eric Lippert (https: //blogs.msdn.microso ft.com/ericlippert/2011/02/03/curiouser-and-curiouser/) qui traite du "modèle de modèle curieusement récurrent" et de la raison pour laquelle cela ne fonctionne pas comme vous le souhaiteriez en C#. –

+0

@Damien_The_Unbeliever wow, c'était * très * rapide. Merci beaucoup pour cela, je ne savais pas que ce que j'ai mis en œuvre est en fait un modèle. Très perspicace. Je me demandais en effet si les avantages de ma mise en œuvre l'emporteraient à l'avenir sur ses inconvénients. Bien que je ne pouvais pas vraiment voir ce que toutes les chutes de ce modèle étaient, je peux maintenant comprendre pourquoi. Si vous écrivez une réponse plus complète, je l'accepterai volontiers. –

+0

Certaines choses que vous ne pouvez pas appliquer ... –

Répondre

0

Merci à @Damien_The_Unbeliever Je sais maintenant que ce que j'ai mis en œuvre est en fait un modèle appelé couriously recurring template pattern (CRTP).

Eric Lippert et Zp Bappi ont écrit sur ce sujet pour les personnes qui s'intéressent à ces sujets.

[I] pratique n il y a des moments où l'utilisation de ce modèle ne vraiment résoudre les problèmes de façon pragmatique qui sont difficiles à modéliser autrement en C#. [...] L'une des raisons pour lesquelles les gens veulent le faire est de faire respecter une contrainte particulière dans une hiérarchie de types.

Cette raison exacte est ce que j'essaie d'atteindre avec mon code.

Mes doutes sur le CRTP sont également mentionnés dans le post de Lippert. Il conseille

penser très dur avant de mettre en œuvre ce genre de modèle curieux en C#

  1. parce qu'il ne croyez-vous pas appliquer réellement la contrainte, il ne
  2. c'est tout simplement parce qu'il fait cuire les nouilles de quelqu'un qui lit le code
0

Si je comprends ce que vous demandez, cela pourrait aider.

public interface IPrototype 
{ 
    Guid Id { get; set; } 
    string Name{ get; set; } 
} 

public interface IHierarchicalPrototype<T> : IPrototype where T:IPrototype 
{ 
    T Parent{ get; } 
    IList<T> Children { get; } 
} 
+0

Ce n'est pas correct. 'interface IEntityPrototype: IHierarchicalPrototype ' permettrait d'ajouter n'importe quel enfant de 'IPrototype' à son' Children'. Je veux que ses enfants soient exclusivement de type 'IEntityPrototype'. –