2010-10-14 2 views
3

Encore une fois, j'espère vraiment que ce n'est pas une question d'opinion; J'essaie de savoir quelle est la meilleure façon de déterminer le type d'un objet qui appartient à une certaine hiérarchie en C#. J'ai deux façons de concevoir mon application:Détermination d'un type d'objet

1 - Utilisez une propriété sur la classe de base:

public abstract class Parent 
{ 
    public abstract TypeOfObject TypeOfObject { get; } 
} 

public class Child1 : Parent 
{ 
    public override TypeOfObject TypeOfObject { get { return TypeOfObject.Child1 } } 

    // ... 
} 

public class Child2 : Parent 
{ 
    public override TypeOfObject TypeOfObject { get { return TypeOfObject.Child2 } } 

    // ... 
} 

public enum TypeOfObject 
{ 
    Child1, 
    Child2 
} 

public static void Main() 
{ 
    Parent p = new Child1(); 

    switch (p.TypeOfObject) 
    { 
     case TypeOfObject.Child1: _doSomethingWithChild1(p);break; 
     case TypeOfObject.Child2: _doSomethingWithChild2(p);break; 
    } 
} 

2 - utiliser l'opérateur

public abstract class Parent 
{ 
    // ... 
} 

public class Child1 
{ 
    // ... 
} 


public class Child2 : Parent 
{  
    // ... 
} 

public enum TypeOfObject 
{ 
    Child1, 
    Child2 
} 

public static void Main() 
{ 
    Parent p = new Child1(); 

    if (p is Child1) _doSomethingWithChild1(p); 
    if (p is Child2) _doSomethingWithChild2(p); 
} 

Quels sont les implications de chaque alternative? Je pense que 2 a un plus grand impact sur les performances car il dépend des métadonnées, mais 1 semble beaucoup moins élégant. De plus, j'ai appris à faire ça en C++ ... Je ne suis pas sûr qu'il soit nécessaire de le faire avec C#.

EDIT 1:

J'ai ajouté le mot-clé override le code ci-dessus.

EDIT 2:

Je suis désolé, je l'ai sans doute pas moi-même clairement. Je vais illustrer mieux:

Par exemple, j'ai un objet WPF Panel qui possède une propriété Children, qui me retourne UIElement s. J'ai besoin de savoir de quel type un certain élément est capable d'agir ... Dans mon cas particulier, l'utilisateur dessine un graphique sur l'écran, donc j'ai besoin de savoir combien de nœuds et combien de connexions sont dessinées pour stocker puis à la base de données. Je ne peux malheureusement pas utiliser le polymorphisme pour ça, n'est-ce pas? Comment saurai-je si je devrais ajouter une ligne à ma table de nœuds ou à ma table de connexions?

+10

Ceci est une erreur de conception OO commune. Tu n'as pas besoin de ça. S'il vous plaît lire sur "polymorphisme", puis fermez la question. –

+0

Il existe de nombreux exemples de la première façon dans le .NET Framework, par exemple, XmlDocument/XmlElement/..., XDocument/XElement/..., LambdaExpression/UnaryExpression/... – dtb

+0

@ S.Lott: +1 :) (bla) – leppie

Répondre

0

Vos exemples d'utilisation sont faux (comme d'autres l'ont dit - utilisez le polymorphisme) mais il peut être raisonnable de demander de quel type est un objet.

j'ai posé une question similaire pour C++ Testing a c++ class for features

En ce qui concerne la différence entre # 1 et # 2. Les deux nécessitent des métadonnées. Dans le cas 1 vous le faites, dans le cas 2 vous utilisez de toute façon les métadonnées faites par le CLR. Le CLR est probablement meilleur que vous et paye de toute façon

Comme toujours - si vous voulez savoir lequel est le plus rapide, les réponses sont simples - mesurez-le et voyez. Je doute qu'il y ait une différence mesurable

+0

"il peut être raisonnable de demander de quel type est un objet." S'il vous plaît fournir un exemple de quand il est réellement "raisonnable" qui n'implique pas assez mauvais polymorphisme. Malheureusement, ** tous ** les exemples d'identification de type run-temps que j'ai jamais vu sont toutes de mauvaises erreurs de polymorphisme. S'il vous plaît clarifier avec un exemple. –

+0

http://stackoverflow.com/questions/3336859/testing-a-c-class-for-features – pm100

+0

@ pm100: Comment n'est-ce pas un autre exemple de mauvais polymorphisme? Cela ressemble à quelque chose qui aurait dû être un simple polymorphisme. Qu'est-ce que j'ai raté? –

4

la première alternative n'est pas nécessaire. Si vous regardez Object (la base de TOUS les objets en C#), vous trouverez un membre GetType().

Dans notre code de production, nous utilisons souvent la méthode 2, principalement pour "down-casting" qui est, jetant une classe de base à une classe qui est dérivée de ladite classe de base ...

if (myObject is Type1) dosomething(); 
if (myObject is Type2) dosomethingelse(); 

nous utilisons également l'opérateur as ....

Type1 object1 = someotherobject as type1; 
if (object1 != null) dosomething(); 

la bonne chose à ce sujet, est que vous n'obtiendrez des exceptions comme vous le feriez si vous avez essayé quelque chose comme ceci:

((TypeFoo)object1).bar(); // if object 1 is NOT of TypeFoo you get an exception 
+0

Voulez-vous dire 'GetType' au lieu de' TypeOf'? – Gabe

+1

Le polymorphisme devrait faire apparaître quelque chose de * différent * selon que 'myObject' est de type' Type1' versus 'Type2' sans avoir à vérifier explicitement. Si vous opérez sur myObject et que vous avez besoin de distinguer son type concret, cela signifie que vous êtes couplé de manière inappropriée et que vous devez refactoriser. – FMM

+0

par tous les moyens, vous devriez utiliser le polymorphisme si vous pouvez, cependant, parfois vous n'avez pas cette option. par exemple, LINQ me donne un IEnumerable, mais si c'est * vraiment * une liste de quelque chose, comment puis-je savoir si je ne le teste pas? –

10

Vous le faites mal ™. Jamais entendu parler de polymorphisme (liaison tardive/dynamique pour être plus précis)? Le parent devrait avoir une méthode abstraite comme doSomething() à être mis en œuvre par les enfants, tout ce qui était en _doSomethingWithChild1 devrait être en Child1.doSomething, etc .. C'est ce que OO est tous - bien, pas tous, mais en grande partie - à propos de! La FAQ C++ a raison de prétendre que C++ ne serait pas orienté objet sans virtual.Il est non seulement plus facile/moins susceptible d'ajouter un autre enfant (vous définissez simplement une nouvelle sous-classe et la méthode, pas besoin de manipuler les switchs ou les ifs) et très probablement le plus rapide possible (chaque JIT vaut polymorphic inline caching), il est aussi idiomatique et moins susceptible de vous donner ce regard "WTF";)

+0

C'est effectivement la même chose qu'une instruction switch. Si vous "basculez" sur le type d'exécution, je suis d'accord, vous faites le mal (TM). Regardez autour de refactoring des déclarations de commutateur au polymorphisme. – FMM

+0

J'ai édité la question afin de produire un exemple plus clair. Les objets peuvent être polymorphes, mais il y aura des moments où j'ai besoin de connaître le type exact d'entre eux. –

+0

@Bruno: Comment exactement l'exemple ne fonctionne pas avec le polymorphisme? Si vous insérez des choses dans une base de données en fonction du type, faites simplement que les objets (polymorphiquement) mettent cette information dans la base de données? – delnan

Questions connexes