Oh boy ai-je passé beaucoup de temps sur ce problème ...Comment utiliser l'objet dérivé dans la liste des baseclass pour l'extension générique
Ce que je suis en train de faire est de cloner un objet de type GameObject
qui a également contient une liste de Component
. Cloner GameObject
types n'est pas un problème, mais il semble que cette liste est un problème car il est cloné mais pas son contenu; Le contenu n'est pas copié mais simplement stocké.
Autant que je voudrais cloner ces composants de la même manière que je l'ai fait avec les gameobjects, ce n'est pas possible à cause de mon système.
Les composants sont attachés à un GameObject
et définissent fondamentalement le GameObject
. Par exemple, si je voulais créer un moyen pour l'utiliser pour contrôler un GameObject
je créerais un composant appelé quelque chose comme PlayerController
qui proviendraient de type de base Component
, en regardant quelque chose comme ceci:
class Component
{
//The gameobject this component is attached to
public GameObject gameObject { get; set;}
public virtual void Update()
{
//..
}
}
class PlayerController : Component
{
override Update()
{
Move();
//..
}
public void Move()
{
//...
}
}
La façon dont je m clonage gameobject est dans une méthode comme ceci:
public GameObject Clone(Vector2 position, float scale)
{
GameObject source = this;
GameObject clone = new GameObject();
//Get all properties of a GameObject
var srcProperties = TypeDescriptor.GetProperties(typeof(GameObject)).Cast<PropertyDescriptor>();
//Assign all properties from the source to the clone
foreach (var srcProperty in srcProperties)
{
srcProperty.SetValue(clone, srcProperty.GetValue(source));
}
//Clone all components from source and add them to the clone
if (source.components.Count > 0)
{
for (int i = source.components.Count - 1; i >= 0; i--)
{
var srcComp = source.components[i];
var compClone = srcComp.CloneComponent();
clone.components.Add(compClone);
}
}
clone.position = position;
clone.scale = scale;
AllGameObjects.Add(clone);
if (clone.components.Count > 0)
{
//Set the owner gameobjects and start the components
for (int i = clone.components.Count - 1; i >= 0; i--)
{
var comp = clone.components[i];
comp.gameObject = clone;
comp.Start();
}
}
return clone;
}
la méthode CloneComponent()
de la ligne 17 var compClone = srcComp.CloneComponent();
est une méthode d'extension générique qui ressemble à ceci:
public static TComponent CloneComponent<TComponent>(this TComponent source) where TComponent : Component, new()
{
TComponent clone = new TComponent();
var srcProperties = TypeDescriptor.GetProperties(typeof(TComponent)).Cast<PropertyDescriptor>();
foreach (var srcProperty in srcProperties)
{
srcProperty.SetValue(clone, srcProperty.GetValue(source));
}
return clone;
}
Cette méthode fonctionne bien, si la source n'a pas été tirée d'une liste de Component
car il semble convertir tout type qu'il était au type racine ce qu'il fait seulement lorsqu'il est utilisé comme argument. Il en résulte évidemment TComponent
étant de type Component
et au lieu de cloner la source, il le convertit simplement en type racine et ne fait que cloner les propriétés de celui-ci.
Ce que je demande est pour un moyen de contourner ceci, ou pour qu'il ne soit pas converti en type racine lorsqu'il est utilisé comme argument?
Edit:
Le type du paramètre source
sera de type correct, mais TComponent
sera toujours de type Component
lorsque l'argument source est donnée comme un argument dans une liste. Vous pourriez penser que je l'explique incorrectement mais je pense que c'est aussi bizarre que vous. La seule chose à laquelle je peux penser est que c'est un bug, ce qui est peu probable.
modifier final:
Merci beaucoup @Philipp pour la suggestion d'utiliser Activator.CreateInstance
. Voici comment je l'ai changé ma méthode CloneComponent()
:
public static Component CloneComponent(this Component source)
{
var clone = Activator.CreateInstance(source.GetType());
var srcProperties = TypeDescriptor.GetProperties(source.GetType()).Cast<PropertyDescriptor>();
foreach (var srcProperty in srcProperties)
{
srcProperty.SetValue(clone, srcProperty.GetValue(source));
}
return (Component)clone;
}
Maintenant que vous le mentionnez, j'ai besoin de faire un edit - La source est du type correct mais TComponent est toujours Component ONLY quand l'argument provient d'une liste. Cela signifie que 'clone' est de type' Component', donc si j'utilise 'source.GetType()' il me donnera une erreur car il essayera d'assigner des valeurs aux propriétés que 'clone' n'a pas.J'ai vraiment du mal à expliquer ce qui se passe ici car cela semble être un résultat très bizarre ... Ce qui est bizarre, c'est que partout où j'appelle 'CloneComponent',' TComponent' sera correct sauf si l'argument provient d'une liste ... –
La sérialisation binaire n'est pas non plus une option puisque j'utilise le framework xna et que je ne peux pas faire des types comme 'Vector2' serializable. –
Cependant, en utilisant Activator.CreateInstance() dans 'CloneComponent' a résolu mon problème, merci beaucoup mon bon monsieur et passez une merveilleuse journée! –