簡體   English   中英

如何在基類列表中使用派生對象進行通用擴展

[英]How to use derived object in list of baseclass for generic extension

哦,男孩,我在這個問題上花了很多時間...

我想做的是克隆一個GameObject類型的對象,該對象還包含一個Component列表。 克隆GameObject類型沒有任何問題,但似乎此列表是一個問題,因為它是克隆的,但不是其內容。 內容不被復制,而是被存儲。

盡管我想像使用游戲對象一樣克隆這些組件,但由於我的系統,這是不可能的。
組件連接到GameObject並基本上定義GameObject 例如,如果我想創建一種用於控制GameObject的方式,則可以創建一個名為PlayerController Component ,該Component將從基本類型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()
    {
        //...
    }
}

我克隆GameObject的方式是這樣的方法:

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行的CloneComponent()方法var compClone = srcComp.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的類型將是正確的類型,但是當source參數作為list的參數給出時, 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()創建實例。 另外,您始終可以對整個樹進行二進制序列化,然后再次進行反序列化,從而為對象圖提供了完整的深層克隆。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM