2010-08-05 21 views
1

Pour expliquer mon problème ici est un exemplePolymorphisme et problème coulée

namespace CheckAbstarct 
{ 

class Program 
{ 
    static void Main(string[] args) 
    { 
     myAbstarctClass mac1 = ObjectFactory.ObjectCreator("aaa"); 
     myAbstarctClass mac2 = ObjectFactory.ObjectCreator("bbb"); 
     mac1.changeMyString(); 
     mac2.changeMyString(); 
     string myString = (string)mac2.returnMyObject(); 
     DateTime myObject = (DateTime) mac1.returnMyObject(); 

     object obj1 = mac1.returnMyObject(); 
     object obj2 = mac2.returnMyObject(); 

     myMethod(obj1); //---> This is not compiling 
     myMethod(obj2); //---> This is not compiling 

     myMethod(myString); //---> works fine 
     myMethod(myObject); //---> works fine 

     Console.ReadKey(); 
    } 
    public static void myMethod(DateTime dt) 
    { 
    } 
    public static void myMethod(string st) 
    { 
    } 
} 
abstract class myAbstarctClass 
{ 
    protected string mMyString; 
    public myAbstarctClass() 
    { 
     mMyString = "myAbstarctClass "; 
    } 
    public abstract void changeMyString(); 
    public abstract object returnMyObject();   
} 

class MyNewAbstractClass1 : myAbstarctClass 
{ 
    DateTime mObject; 
    public MyNewAbstractClass1(string myString) 
    { 
     mMyString = myString; 
     mObject = new DateTime().Date; 
    } 
    public override void changeMyString() 
    { 
     mMyString += " MyNewAbstractClass1"; 
     Console.WriteLine(mMyString); 
    } 
    public override object returnMyObject() 
    { 
     return mObject; 
    } 
} 

class MyNewAbstractClass2 : myAbstarctClass 
{ 
    string mString; 
    public MyNewAbstractClass2(string myString) 
    { 
     mMyString = myString; 
     mString = mMyString; 
    } 
    public override void changeMyString() 
    { 
     mMyString += " MyNewAbstractClass2"; 
     Console.WriteLine(mMyString); 
    } 
    public override object returnMyObject() 
    { 
     return mString; 
    } 
} 

static class ObjectFactory 
{ 
    public static myAbstarctClass ObjectCreator(string myString) 
    { 
     switch (myString) 
     { 
      case "aaa": 
       return new MyNewAbstractClass1(myString); 
      case "bbb": 
       return new MyNewAbstractClass2(myString); 
      default: 
       return null; 
     } 
    } 
}  
} 

Mon problème est que dans Main() Je ne sais pas quel type de la méthode returnMyObject() retourne donc je ne peux pas envoyez-le à MyMethod. Y a-t-il un moyen de lancer les objets ??

+0

Peut-être que vous devriez utiliser (typeof (obj1)) obj1? –

+0

Le problème que vous rencontrez est un symptôme de mauvaise conception - ce n'est pas vraiment la façon dont le polymorphisme est censé être utilisé. L'héritage est censé être une relation "est-un" (par exemple. 'MyNewAbstractClass1' IS-A' myAbstarctClass', 'MyNewAbstractClass2' IS-A' myAbstarctClass'). Toutes les fonctions qui opèrent sur le type abstrait ou l'un de ses sous-types devraient pouvoir le faire sans connaître le type spécifique de l'objet (et dans votre cas devrait lister 'myAbstarctClass' comme le type de paramètre représentant l'objet).Pas besoin de connaître le type réel est la puissance réelle derrière Polymorphisme. – MatthewD

+0

Alors, quelle est votre suggestion à ce problème. Quelle solution considéreriez-vous comme un bon design pour ce genre de problème? – user411931

Répondre

5

Parce que dans votre conception de returnMyObject() vous êtes retourné à object les plus courantes des références, vous devrez trouver dans l'exécution:

if (obj1 is string) 
    myMethod((string)obj1); //--->cast it 
else if (obj1 is DateTime) 
    myMethod((DateTime) obj1); 
+0

Pourquoi ne pas utiliser obj1.ToString() – Gage

+1

@Gage: Je voulais montrer un modèle avec 2 types. chaîne est un peu privilégié, je ne voulais pas l'utiliser ici. Et ToString n'est pas vraiment meilleur ou plus rapide ici. –

4

Vous pouvez vérifier le type de l'objet à l'exécution:

 
public static void myMethod(Object o) 
{ 
    if (o is DateTime) 
     myMethod((DateTime)o); 
    else if (o is string) 
     myMethod((string)o); 
} 

bien que dans votre cas, vous pourriez tout aussi bien passer une instance myAbstarctClass-myMethod, puis appelez returnMyObject() là.

0

Non, vous devez soit créer commutateur avec toutes les possibilités, ou quelque chose comme Dictionary<Type, Delegate>

ou vous pouvez simplement faire myMethod (objet obj)

il est appelé envoi multiple (http://en.wikipedia.org/wiki/Multiple_dispatch) et il y a des bibliothèques qui peut le faire

1

Vous pouvez soit utiliser la fonction dynamique de C# 4.0 ou la conception de changement d'utiliser une sorte de technique de double expédition

 dynamic obj1 = mac1.returnMyObject(); 
     dynamic obj2 = mac2.returnMyObject(); 
1

Utiliser des mécanismes Polymorphisme de sorte que vous ne pas besoin de connaître le type d'objet.

Faire myMethod une méthode abstraite de myAbstarctClass et fournir des implémentations à la fois dans MyNewAbstractClass1 et MyNewAbstractClass2.

Modifier myAbstractClass1.returnMyObject() pour renvoyer myAbstarctClass (pas object).

Le code de test en Main peut alors écrire:

... 
myAbstarctClass obj1 = mac1.returnMyObject(); 
myAbstarctClass obj2 = mac2.returnMyObject(); 

obj1.myMethod();  // calls MyNewAbstractClass1.myMethod() 
         // no if statement required! 

obj2.myMethod();  // calls MyNewAbstractClass2.myMethod() 
         // no if statement required! 

Console.ReadKey(); 

Edit: Ceci peut être encore simplifiée, puisque les méthodes ne sont returnMyObject() plus nécessaires - ils reviennent tout l'objet que vous avez déjà. Le code de test est maintenant simplement:

mac1.myMethod(); 
mac2.myMethod(); 

// etc... 
Console.ReadKey(); 
+0

Merci, mais l'idée est que MyMethod est une méthode qui devrait fonctionner sur l'information (dans le futur) que je ne veux pas le myAbstracts objet savoir sur – user411931

+0

Sans aucune information sur ce que myMethod fait il est assez difficile de fournir une solution raisonnable à votre problème. J'ai cependant une autre idée, que je posterai comme nouvelle réponse. – MatthewD

0

Puisque vous semblez utiliser votre classe en tant que conteneur pour un type, peut-être Generics serait un être meilleur choix que l'héritage (par exemple DateTime, string.):

namespace CheckAbstract 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      myTemplateClass<DateTime> mac1 = new myTemplateClass<DateTime>(new DateTime().Date); 
      myTemplateClass<string> mac2 = new myTemplateClass<string>("cat dog"); 

      mac1.changeMyString(); 
      mac2.changeMyString(); 
      string myString = (string)mac2.returnMyObject(); 
      DateTime myObject = (DateTime) mac1.returnMyObject(); 

      myMethod<string>(myString); 
      myMethod<DateTime>(myObject); 

      Console.ReadKey(); 
     } 

     public static void myMethod<T>(T obj) 
     { 
     } 
    } 

    class myTemplateClass<T> 
    { 
     T mObject; 
     string mMyString; 
     public myTemplateClass(T init) 
     { 
      mMyString = init.ToString(); 
      mObject = init; 
     } 
     public void changeMyString() 
     { 
      mMyString += " " + mObject.ToString(); 
      Console.WriteLine(mMyString); 
     } 
     public T returnMyObject() 
     { 
      return mObject; 
     } 
    } 
}