2017-07-31 225 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

看看我的编辑。 –

相关问题