2008-11-04 9 views
4

J'utilise un exemple fictif pour cela. Dites, j'ai une classe Widget:Générique Parent Pour Générique Classe

abstract class Widget 
{ 
Widget parent; 
} 

Maintenant, mes autres classes seraient dérivées de cette classe Widget, mais suppose que je veux mettre une contrainte dans la classe tout en définissant les types dérivés tels que seul un particulier "type" de widget peut ê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 en tant que WidgetParent, afin que je ne doive pas taper cast le parent chaque fois que je l'utilise.

Précisément, ce que je l'aurais aimé faire est la suivante:

// This does not works! 
class Widget<PType>: where PType: Widget 
{ 
    PType parent; 
} 

class WidgetParent<Widget> 
{ 
    public void Slap(); 
} 

class WidgetChild<WidgetParent> 
{ 
} 

Alors que lorsque je veux accéder au parent de WidgetChild, au lieu de l'utiliser de cette façon:

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

I vouloir l'utiliser de cette façon (si je pouvais utiliser des génériques):

wc.parent.Slap(); 

Répondre

8

Vous devriez être en mesure d'utiliser le code que vous avez en ayant toujours la classe non générique Widget et faire Widget<T> en tirer:

public abstract class Widget 
{ 
} 

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

Vous devez ensuite travailler ce qui appartient au générique classe et ce qui appartient au non-générique ... par expérience, cela peut être un acte d'équilibre délicat. Attendez-vous à aller et venir une bonne quantité!

0

Je ne pense pas qu'il existe un mécanisme de langue qui w ould vous permettre de faire cela.

Toutefois, vous pouvez utiliser un Factory pattern pour séparer la construction de la classe de la classe.

Say, faire une classe WidgetFactory

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

Et pour les classes d'enfants, vous feriez leur usine aussi bien. Dites, un WidgetParentFactory ou WidgetChildFactory ou vous pourriez faire une usine générique:

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

Ensuite, à partir de la méthode createWidget(), vous pouvez contrôler l'instanciation de classe afin que les types d'enfants invalides ne peuvent pas être créés.

class WidgetFactory<T> 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.

p.s. Souhaitez-vous élaborer sur pourquoi vous vouliez faire cela?

+0

Merci pour l'effort , chakrit. J'ai élaboré l'usage. – nullDev

+0

Ok, je vois maintenant. Éditera quand je serai à la maison. – chakrit

0

Vous semblez confondre les paramètres de type et l'héritage.Cela devrait fonctionner:

class Widget<PType> where PType :new() 
{ 
    public PType parent = new PType(); 
} 

class ParentType {} 

class WidgetParent : Widget<ParentType> 
{  
    public void Slap() {Console.WriteLine("Slap"); } 
} 

class WidgetChild : Widget<WidgetParent> 
{ 
} 
public static void RunSnippet() 
{ 
    WidgetChild wc = new WidgetChild(); 
    wc.parent.Slap(); 
} 
+0

Je pensais que le but était de contraindre le type parent à être aussi un widget quelconque. –

+0

@Jon: Exactement, le parent a la dite contrainte. – nullDev

1

Utiliser les interfaces:

interface IContainerWidget { } 

class Widget 
{ 
    private IContainerWidget Container; 
} 

class ContainerWidget : Widget, IContainerWidget 
{ 
} 
0

Voici mon coup de couteau à l'organisation de cette.

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(); 
    } 
} 
0

J'ai eu un problème similaire et adapté à baggages (espérons)

Code principal

public class Parent<T> 
    where T : Child<T> 
{ 
    public Parent() { } 


    public T Get() 
    { 
     return Activator.CreateInstance(typeof(T), new object[] { this }) as T; 
    } 
} 

public class Child<T> 
    where T : Child<T> 
{ 
    Parent<T> _parent; 

    public Parent<T> Parent { get { return _parent; } } 

    public Child(Parent<T> parent) 
    { 
     _parent = parent; 
    } 
} 


public class ItemCollection : Parent<Item> 
{ 

} 

public class Item : Child<Item> 
{ 
    public Item(Parent<Item> parent) 
     : base(parent) 
    { 
    } 
} 

Exemple:

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