2010-08-07 11 views
1

Étant donné ces classes C# (généré par la WCF, je ne peux pas changer ces):Les classes dérivées comme valeur de retour

public SysState GetSysState(); 

public class SysState { /* nothing much here */} 
public class Normal : SysState { /* properties & methods */ } 
public class Foobar : SysState { /* different properties & methods */ } 

Mon code (actuellement):

SysState result = GetSysState(); 

if (result is Normal) HandleNormal((Normal) result); 

if (result is Foobar) HandleFoobar((Foobar) result); 

Ma question: Je continue à sentir qu'il me manque quelque chose d'évident, que je ne devrais pas avoir besoin de vérifier le type explicitement. Est-ce que j'ai un moment senior?

Répondre

1

Utilisez une méthode virtuelle. Mettez votre code dans les classes sur lesquelles ils opèrent, pas dans du code qui obtient une référence à la classe.

public class SysState { 
    /* nothing much here, except...: */ 
    public abstract virtual void DoSomething(); 
} 

public class Normal : SysState { 
    /* properties & methods */ 
    public override void DoSomething() 
    { 
    // ... 
    } 
} 

public class Foobar : SysState { 
    /* different properties & methods */ 
    public override void DoSomething() 
    { 
    // ... 
    } 
} 

SysState result = SomeFunctionThatReturnsObjectDerivedFromSysState(); 

result.DoSomething(); 

Ceci exécutera la méthode DoSomething de la classe dérivée. C'est ce qu'on appelle le polymorphisme, et c'est le plus naturel (et certains diraient le seul correct) l'utilisation de l'héritage.

Veuillez noter que SysState.DoSomething n'a pas besoin d'être abstrait pour que cela fonctionne, mais il doit être virtuel.

+0

+1 Je vais essayer, merci. – egrunin

+0

@egrunin: Si vous ne pouvez absolument pas modifier les classes, alors vous ne pouvez évidemment pas faire cela, et vous devrez utiliser "si c'est un type ... else si c'est un autre type ..." . Cependant, vous pouvez écrire vos propres classes wrapper sur le côté client pour prendre soin de ce problème pour vous. Les classes wrapper auraient ces classes comme leur guts, et fournir une interface publique qui fait du polymorphisme. Vous auriez toujours besoin du "si ce type, alors ...", mais vous auriez seulement à l'écrire une fois, où il convertit les types à vos wrappers. –

0

Vous pouvez essayer combiner handleX et placer Handle dans SysState et plus-riding dans les deux Normal et Foobar pour effectuer des tâches spécifiques. Ce n'est peut-être pas la solution parfaite, mais il semblerait relativement soigné. Si vous avez besoin d'entrer des données provenant d'autres sources, passez-les en tant que paramètres?

public class SysState 
{ 
    public bool Process(Information info) 
    { 
     return (info.Good); 
    } 
} 

public class Normal 
{ 
    public bool Process(Information info) 
    { 
     return doStuff(); 
    } 
} 

public class Foobar 
{ 
    public bool Process(Information info) 
    { 
     return diePainfully(); 
    } 
} 

Il est évident qu'un exemple, ne sachant pas ce que HandleNormal et HandleFoobar faire, mais il pourrait fonctionner très bien.

+0

Je ne peux pas changer ces classes, elles sont générées automatiquement. Lorsque le WDSL change, toutes les personnalisations seront perdues. Sinon oui, ce serait bien. – egrunin

+0

Ah. Eh bien, cela ne fonctionnera pas du tout alors. Pourriez-vous les convertir en un type commun qui a une fonction de traitement pour gérer les différences? – ssube

+5

Marquez simplement votre classe personnalisée. svcutil le fait déjà avec les classes générées. Vous pouvez mettre tout votre code personnalisé dans votre propre classe sans avoir à vous soucier du code généré lors de la modification de wsdl. –

Questions connexes