创建泛型类型的新实例会转换为根类型吗?

时间:2017-07-31 22:58:16

标签: c# generics xna polymorphism

我目前正在尝试克隆我的XNA项目中的自定义类型,我称之为“#34; Component"”,看起来像这样。

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的类,我试图克隆它。

例如,我可能有一个名为&#34; PlayerController&#34;:

的组件
class PlayerController: Component

所以如果我想克隆一个PlayerController我输入那个作为类型参数; TComponent应为PlayerController类型。

所以,让我们说我试图克隆一个PlayerController组件。

如果我调试源组件的名称,即组件中的GetType().ToString()

Debug.WriteLine(source.name);

我得到输出&#34; PlayerController&#34;。

这意味着TComponent的类型为PlayerController,对吧?

但是,如果我调试克隆的名称,TComponent的新实例,我得到输出&#34;组件&#34;。这意味着由于某种原因,我的新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
的PlayerController

这意味着TComponent实际上是源的类型。

当我做同样的事情时,我怎么没有在我的项目中得到相同的结果?

编辑2
source参数取自Components列表,因此当用作参数时,它显然会转换为root类型...当我调试它之前,它正确地键入了它给我正确的类型。我想我不得不再提出一个关于如何绕过这个问题的问题。

2 个答案:

答案 0 :(得分: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";
    }
}

答案 1 :(得分:0)

我认为你缺少的是C#中的泛型类型在编译时被实例化。这意味着TComponent的类型是根据您传入source的{​​{1}}的(静态编译时)类型设置的。编译器无法看到CloneCompenent中包含的实际对象可能属于另一种类型的事实。

由于您无法知道对象的动态类型,因此必须使用继承并将克隆操作委派给实际类型。在Component类中:

source

在PlayerComponent类中:

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