如何使用派生类对象的基类的列表通用扩展

问题描述:

哦,孩子有我花了很多时间在这个问题...如何使用派生类对象的基类的列表通用扩展

我试图做的是克隆GameObject类型的对象也包含一列Component。克隆GameObject类型没有任何问题,但似乎这个列表是一个问题,因为它被克隆而不是它的内容;内容不会被复制,只会被存储。

就像我想用克隆这些组件的方式克隆这些组件一样,因为我的系统,这是不可能的。
组件连接到GameObject,基本上定义了GameObject。例如,如果我想创造一种方式,使用来控制GameObject我会创建一个名为像PlayerController组件时,它从基础型Component,看起来像这样得到:

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() 
    { 
     //... 
    } 
} 

我的方式米克隆游戏对象是在这样的方法:

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; 
} 

从第17行的var compClone = srcComp.CloneComponent();方法CloneComponent()是一个通用的扩展方法,看起来像这样:

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; 
} 

如果源不是从Component的列表中获取的,则该方法可以正常工作,因为它似乎将其转换为仅用于作为参数的参数的根类型。这显然导致TComponent的类型为Component,而不是克隆源代码,它只是将其转换为根类型,并且只从中克隆属性。

我要求的是一种方法来绕过这个,或者它作为参数时不转换为根类型?

编辑:

参数类型source将是正确的类型的,但是TComponent永远是Component类型的源时参数被给定为从列表
参数。你可能会认为我正在解释这个错误,但我认为它和你一样奇怪。我能想到的唯一的事情就是它是一个错误,我认为这不太可能。

最后编辑:
非常感谢你对@Philipp使用Activator.CreateInstance建议。这是我改变了我的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; 
} 

source.GetType()而不是typeof(TComponent)应该返回实际(继承)类型,你可以创建一个使用Activator.CreateInstance()一个实例。此外,您可以始终对整个树进行二进制序列化并再次反序列化,从而为您提供对象图的完整深度克隆。

+0

现在你提到它了,我需要进行编辑 - 源代码是正确的类型,但TComponent总是只有当参数来自列表时才是Component。这意味着'clone'的类型是'Component',所以如果我使用'source.GetType()',它会给我一个错误,因为它会试图给'clone'没有的属性赋值。我真的很难解释这里发生了什么,因为它看起来像是一个非常奇怪的结果......奇怪的是,无论我在哪里调用CloneComponent,除了从列表中获取参数外,“TComponent”都是正确的... –

+0

另外二进制序列化不是一个选项,因为我使用xna框架,并且不能像'Vector2'可序列化的类型。 –

+0

虽然在CloneComponent中使用Activator.CreateInstance()解决了我的问题,但非常感谢你,我的好先生,祝你有美好的一天! –