2017-07-31 179 views
1

我目前正在嘗試克隆我稱爲「Component」的XNA項目中的自定義類型,讓它看起來像這樣。創建新的泛型類型實例轉換爲根類型?

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

在我的項目,居然還有克隆代碼在我的方法,但由於它沒有任何關係我的問題做我刪除它。

對於我的組件類的一些解釋,我有根類稱爲Component但後來我創建從Component派生的類,我試圖克隆。

因此,舉例來說,我可能已經調用組件「的PlayerController」:

class PlayerController: Component 

所以,如果我想克隆一個PlayerController I輸入,作爲類型參數; TComponent應該是PlayerController類型。我們假設我試圖克隆PlayerController組件。

如果我調試的源組件,它是在組件GetType().ToString()名稱:

Debug.WriteLine(source.name); 

我得到的輸出「的PlayerController」。

所以這意味着TComponentPlayerController類型,對不對?

但是,如果我調試克隆的名稱,TComponent的新實例,我會得到輸出「組件」。這意味着由於某種原因,我的新實例TComponent已轉換爲根類型??

有趣的是,當我重新創建一個控制檯應用程序,我沒有得到這個錯誤...

編輯

測試來源:

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

什麼控制檯中的這個輸出是:

PlayerController
Play erController

這意味着TComponent實際上是源的類型。

當我做完完全相同的事情時,我在項目中沒有得到相同的結果?

編輯2
源參數是從組件列表拍攝,因此顯然作爲參數使用時將它轉換成根型......當我調試它是正確鍵入它給我的前正確的類型。我想我只能提出另一個關於如何繞過這個問題的問題。

+0

您能得到什麼,如果你調試'typeof運算(TComponent)的ToString()'在功能或放在一個變量來檢查像'var x = new TComponent()'? – NetMage

+0

@NetMage看起來像我得到的根類型... –

+0

所以現在你知道'TComponent'的類型。 – NetMage

回答

0

我不太確定你的實際問題是什麼。你的代碼看起來很好,似乎給你像你想要的PlayerController。如果我運行下面的代碼,我得到:

Source: Tester.PlayerComponent, clone: Tester.PlayerComponent 

來源:

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

我的代碼看起來不錯,但它並不像我想要的那樣給我PlayerController。當我創建一個新的TComponent'TComponent clone = new TComponent();''clone'的類型總是Component,即使源的類型不是。 –

+0

上面的示例代碼中是否存在缺失的內容? item2被視爲類型PlayerComponent。 – jeremywho

+0

沒有什麼缺失,當我在控制檯應用程序中嘗試此操作時,我還在項目2上獲得PlayerComponent作爲類型。但在我的項目中,TComponent始終是根類型Component,當我創建它的一個新實例'TComponent clone = new TComponent();' –

0

我認爲你缺少的是,在C#泛型類型是在編譯時實例化。這意味着TComponent的類型是基於source的(靜態編譯時)類型設置的,您可以將其輸入CloneCompenent。編譯器無法看到source中包含的實際對象可能是另一種類型的事實。

由於無法知道對象的動態類型,因此必須使用繼承並將克隆操作委託給實際類型。在組件類:

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

在PlayerComponent類:

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

但是,這不僅僅返回基類型「Component」的對象嗎?我看到這種演變成XY的問題,我真的沒有想到,對不起...... –

+0

不,它會返回任何類型的對象。它們將被存儲在一個類型爲'Component'的變量中,這可能是由於繼承造成的,但實際的(運行時)類型將來自克隆對象。您可能想了解更多有關繼承的內容。 – NetMage

+0

看看我的編輯。 –