2011-06-10 5 views
2
abstract class A<T> where T:A<T> 
{ 
    public event Action<T> Event1; 
} 

class B : A<B> 
{ 
    //has a field called Action<B> Event1; 
} 

Y at-il une façon plus élégante de faire cela? Je veux que des choses (événements, etc.) dans la classe de base puissent utiliser le type de la sous-classe.La meilleure façon de se référer à mon propre type

+0

Attention, une classe de base ne doit pas avoir une connaissance directe de celui-ci est sous-classe, il devient un sale de la dette technique. Dans ce cas, puisque c'est un générique ce n'est pas trop mal, mais juste en général. –

+1

Ne voulez-vous pas dire «où T: A »? Eric Lippert a déjà écrit à ce sujet: http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx –

Répondre

4

Le motif que vous utilisez n'implémente pas réellement la contrainte souhaitée. Supposons que vous voulez modéliser « un animal ne peut être amical avec quelque chose de sa propre espèce »:

abstract class Animal<T> where T : Animal<T> 
{ 
    public abstract void GetFriendly(T t); 
} 

class Cat : Animal<Cat> 
{ 
    public override void GetFriendly(Cat cat) {} 
} 

Avons-nous réussi à mettre en œuvre la contrainte souhaitée? Maintenant, un chien maléfique peut être amical avec n'importe quel chat, et pas amical avec d'autres chiens méchants.

La contrainte de type que vous souhaitez n'est pas possible dans le système de type C#. Essayez Haskell si vous avez besoin de ce genre de contrainte appliquée par le système de types.

Voir mon article sur ce sujet pour plus de détails:

http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx

+0

Je pense que vous signalez une limitation importante, mais en fonction sur les exigences réelles cela peut ou peut ne pas être un problème sérieux. Par exemple, si cela est utilisé uniquement dans son propre code, il peut être stylistiquement évident si le modèle est implémenté correctement. – kvb

+0

Intéressant prendre cela. Je suis complètement en désaccord. Il existe une solution simple au problème que vous percevez existe avec cette technique. http://blog.theobjectguy.com/2011/06/curiously-recurring-template-pattern.html – TheObjectGuy

1

Ce que vous avez fonctionne très bien. En fait, il est très similaire à d'autres interfaces .NET et types où vous voulez que l'implémenteur interface pour utiliser votre type, comme:

public class MyClass : IEqualityComparer<MyClass> 
{ 
    // From the interface IEqualityComparer 
    public bool Equals(MyClass other) { ... } 

    ... 
} 
0

Puisque A est abstraite, vous pouvez ajouter des méthodes abstraites à A et les invoquerez A et B, qui sera obligé de mettre en œuvre la méthode, sera l'invocateur:

abstract class A<T> where T:A 
{ 
    public event Action<T> Event1; 
    public abstract void Method(); 

    public A(){Method();} 
} 

class B : A<B> 
{ 
    //has a field called Action<B> Event1; 
    public void Method(){ //stuff } 
} 

sur instanciation de B, le constructeur de la classe de base appellera() qui est uniquement mis en œuvre en B, forçant l'instance de B à appeler .

Cela permet à A d'invoquer des méthodes spécifiques à une sous-classe sans que A ait besoin d'avoir des connaissances spécifiques sur les enfants. L'inconvénient est que TOUS les enfants doivent implémenter la Méthode ou la résumer à leurs propres enfants.

Questions connexes