2017-07-31 3 views
1

J'essaye actuellement de cloner un type personnalisé dans mon projet XNA que j'appelle "Component", en le faisant ressembler à ceci.Créer une nouvelle instance de type générique convertit en type racine?

public static TComponent CloneComponent<TComponent>(this TComponent source) where TComponent : Component, new() 
{ 
    TComponent clone = new TComponent(); //Create the new instance 

    //Clone the source code here 

    return clone; 
} 

Dans mon projet, il est en fait le code du clonage dans ma méthode, mais comme il n'a rien à ma question de faire je l'ai enlevé.

Pour une explication sur ma classe de composant, j'ai la classe racine appelée Component mais ensuite je crée des classes qui dérivent de Component que j'essaye de cloner.

Ainsi, par exemple, je pourrais avoir un composant appelé "PlayerController":

class PlayerController: Component 

Donc, si je veux cloner une entrée PlayerController I que l'argument de type; TComponent doit être de type PlayerController.

Supposons que j'essaie de cloner un composant PlayerController.

Si je déboguer le nom du composant source, qui est GetType().ToString() dans le composant:

Debug.WriteLine(source.name); 

je reçois la sortie « PlayerController ».

Donc, cela signifie que TComponent est de type PlayerController, n'est-ce pas?

Cependant, si je débogue le nom du clone, une nouvelle instance de TComponent, j'obtiens la sortie "Component". Cela signifie que pour une raison quelconque, ma nouvelle instance de TComponent a été convertie en type racine?

Ce qui est intéressant est que quand je recrée cela dans une application console, je ne comprends pas cette erreur ...

Modifier:

Test à la source:

static class Program 
{ 
    static void Main(string[] args) 
    { 
     PlayerController e = new PlayerController(); 
     PlayerController eClone = Extensions.CloneComponent(e); 

     Console.WriteLine(e.name); 
     Console.WriteLine(eClone.name); 
    } 


} 

public class Component 
{ 

} 

public class PlayerController : Component 
{ 

} 

public static class Extensions 
{ 
    public static TComponent CloneComponent<TComponent>(this TComponent source) where TComponent : Component, new() 
    { 
     var clone = new TComponent(); 

     var srcProperties = System.ComponentModel.TypeDescriptor.GetProperties(typeof(TComponent)).Cast<System.ComponentModel.PropertyDescriptor>(); 

     foreach (var srcProperty in srcProperties) 
     { 
      srcProperty.SetValue(clone, srcProperty.GetValue(source)); 
     } 

     return clone; 
    } 
} 

Qu'est-ce que cette sorties dans la console est:

PlayerController
Jouer erController

Cela signifie que TComponent est en fait le type de la source. Comment ne pas obtenir les mêmes résultats dans mon projet quand je fais exactement la même chose?

Edit 2:
Le paramètre source est prise à partir d'une liste des composants, et donc apparemment il est converti en type de racine quand il est utilisé comme argument ... Quand je le débugger est bon type avant qu'il me donne la type correct. Je suppose que je vais devoir faire une autre question sur la façon de contourner cela.

+0

Qu'est-ce que vous obtenez si vous déboguez 'typeof (TComponent) .ToString()' dans la fonction ou mettre dans une variable pour vérifier comme 'var x = new TComponent()'? – NetMage

+0

@NetMage On dirait que j'obtiens le type racine ... –

+0

Donc maintenant vous connaissez le type de 'TComponent'. – NetMage

Répondre

0

Je ne sais pas vraiment quelle est votre véritable question. Votre code semble bien et semble vous donner le PlayerController comme vous le souhaitez.Si je lance le code ci-dessous, je reçois:

Source: Tester.PlayerComponent, clone: Tester.PlayerComponent 

Source:

namespace Tester 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var item = new PlayerComponent() {Name = "PlayerOne"}; 
      var item2 = item.CloneComponent(); 

      Console.ReadLine(); 
     } 
    } 


    public static class Extensions 
    { 
     public static TComponent CloneComponent<TComponent>(this TComponent source) where TComponent : Component, new() 
     { 
      TComponent clone = new TComponent(); //Create the new instance 

      //Clone the source code here   
      Console.WriteLine($"Source: {source.GetType()}, clone: {clone.GetType()}"); 

      return clone; 
     } 
    } 

    public class Component 
    { 
    } 

    public class PlayerComponent : Component 
    { 
     public string Name { get; set; } = "Test"; 
    } 
} 
+0

Mon code semble bien, mais il ne me donne pas PlayerController comme je le veux. Lorsque je crée un nouveau TComponent 'TComponent clone = new TComponent();' le type de 'clone' est toujours Component, même si le type de la source ne l'est pas. –

+0

Y at-il quelque chose qui manque dans mon exemple de code ci-dessus? item2 est vu comme type PlayerComponent. – jeremywho

+0

Il n'y a rien manquant, je reçois également PlayerComponent sur l'élément 2 comme le type lorsque j'essaye ceci dans une application de console. Mais dans mon projet, TComponent est toujours le type racine, Component, quand je crée une nouvelle instance de celui-ci 'TComponent clone = new TComponent();' –

0

Je pense que ce qui vous manque est que les types génériques en C# sont instanciés au moment de la compilation. Cela signifie que le type de TComponent est défini en fonction du type (de compilation statique) du source que vous transmettez à CloneCompenent. Le fait que l'objet réel contenu dans ce source puisse être d'un autre type ne peut pas être vu par le compilateur.

Puisque vous ne pouvez pas connaître le type dynamique de votre objet, vous devez utiliser l'héritage et déléguer l'opération de clonage au type réel. Dans la classe de composants:

public static Component CloneComponent(this Component source) => return source.CloneMyself(); 

Dans la classe PlayerComponent:

public Component CloneMyself() { 
    var clone = new PlayerComponent(this); // special constructor takes self type 
    return (Component) clone; 
} 
+0

Mais cela ne retournera-t-il pas seulement les objets de type 'Component'? Je vois ce genre de problème évolué en XY auquel je ne m'attendais vraiment pas, désolé ... –

+0

Non, il retournera des objets de n'importe quel type sur lequel il est appelé. Ils seront stockés dans une variable de type 'Component' qui est possible en raison de l'héritage, mais le type réel (runtime) proviendra de l'objet cloné. Vous voudrez peut-être en lire plus sur l'héritage. – NetMage

+0

Jetez un oeil à mon édition. –