Parent générique pour la classe générique

J’utilise un exemple fictif pour cela. Dis, j’ai une classe Widget comme:

abstract class Widget { Widget parent; } 

Maintenant, mes autres classes seraient dérivées de cette classe Widget, mais supposons que je veuille mettre une contrainte dans la classe tout en définissant les types dérivés, de sorte que seul un “type” de widget puisse être parent d’un type particulier de Widget.

Par exemple, j’ai dérivé deux autres widgets de la classe Widget, WidgetParent et WidgetChild. Lors de la définition de la classe enfant, je souhaite définir le type de parent comme WidgetParent, afin que je n’ai pas à taper cast le parent à chaque fois que je l’utilise.

Justement, ce que j’aurais aimé faire, c’est ceci:

 // This does not works! class Widget: where PType: Widget { PType parent; } class WidgetParent { public void Slap(); } class WidgetChild { } 

Ainsi, lorsque je veux accéder au parent de WidgetChild, au lieu de l’utiliser comme suit:

 WidgetParent wp = wc.parent as WidgetParent; if(wp != null) { wp.Slap(); } else throw FakeParentException(); 

Je veux l’utiliser de cette façon (si je pouvais utiliser des génériques):

 wc.parent.Slap(); 

Vous devriez pouvoir utiliser le code que vous avez en ayant toujours la classe Widget non générique et en faisant en sorte que Widget dérive:

 public abstract class Widget { } public abstract class Widget : Widget where T : Widget { } 

Vous devez ensuite déterminer ce qui appartient à la classe générique et ce qui appartient au non-générique … Par expérience, cela peut être un exercice d’équilibre délicat. Attendez-vous à aller et venir une bonne quantité!

Utiliser des interfaces:

 interface IContainerWidget { } class Widget { private IContainerWidget Container; } class ContainerWidget : Widget, IContainerWidget { } 

Je ne pense pas qu’il existe un mécanisme linguistique qui vous permettrait de le faire.

Toutefois, vous pouvez utiliser un modèle Factory pour séparer la construction de la classe de la classe elle-même .

Dites, faites une classe WidgetFactory

 class WidgetFactory { Widget CreateWidget() { return new Widget(); } } 

Et pour les classes d’enfants, vous feriez aussi leur usine. Dites, un WidgetParentFactory ou WidgetChildFactory ou vous pouvez créer une fabrique générique:

 class WidgetFactory where T : Widget { T CreateWidget() { return new T(); } } 

Ensuite, à l’aide de la méthode CreateWidget (), vous pouvez contrôler l’instanciation de classe afin que des types enfants non valides ne puissent pas être créés.

 class WidgetFactory where T : Widget { T CreateWidget() { if (/*check the type T inheritance here*/) return new T(); else throw new Exception("Invalid inheritance"); } } 

Cela devrait faire l’affaire pour vous.

ps Voulez-vous préciser pourquoi vous avez voulu faire cela?

Vous semblez confondre les parameters de type et l’inheritance. Cela devrait fonctionner:

 class Widget where PType :new() { public PType parent = new PType(); } class ParentType {} class WidgetParent : Widget { public void Slap() {Console.WriteLine("Slap"); } } class WidgetChild : Widget { } public static void RunSnippet() { WidgetChild wc = new WidgetChild(); wc.parent.Slap(); } 

Voici mon coup pour organiser cela.

 public interface IWidget { void Behave(); IWidget Parent { get; } } public class AWidget : IWidget { IWidget IWidget.Parent { get { return this.Parent; } } void IWidget.Behave() { this.Slap(); } public BWidget Parent { get; set; } public void Slap() { Console.WriteLine("AWidget is slapped!"); } } public class BWidget : IWidget { IWidget IWidget.Parent { get { return this.Parent; } } void IWidget.Behave() { this.Pay(); } public AWidget Parent { get; set; } public void Pay() { Console.WriteLine("BWidget is paid!"); } } public class WidgetTester { public void AWidgetTestThroughIWidget() { IWidget myWidget = new AWidget() { Parent = new BWidget() }; myWidget.Behave(); myWidget.Parent.Behave(); } public void AWidgetTest() { AWidget myWidget = new AWidget() { Parent = new BWidget() }; myWidget.Slap(); myWidget.Parent.Pay(); } public void BWidgetTestThroughIWidget() { IWidget myOtherWidget = new BWidget() { Parent = new AWidget() }; myOtherWidget.Behave(); myOtherWidget.Parent.Behave(); } public void BWidgetTest() { BWidget myOtherWidget = new BWidget() { Parent = new AWidget() }; myOtherWidget.Pay(); myOtherWidget.Parent.Slap(); } } 

J’ai eu un problème similaire et je l’ai adapté pour l’adapter à (espérons-le)

Code principal

 public class Parent where T : Child { public Parent() { } public T Get() { return Activator.CreateInstance(typeof(T), new object[] { this }) as T; } } public class Child where T : Child { Parent _parent; public Parent Parent { get { return _parent; } } public Child(Parent parent) { _parent = parent; } } public class ItemCollection : Parent { } public class Item : Child { public Item(Parent parent) : base(parent) { } } 

Exemple :

 ItemCollection col = new ItemCollection(); Item item = col.Get(); item.Parent.Slap();