【问题标题】:How can I store and use an array of different types derived from a common base type?如何存储和使用从公共基本类型派生的不同类型的数组?
【发布时间】:2011-06-17 20:34:24
【问题描述】:

标题可能需要一些解释,所以这就是我想要做的:

  • UI 元素的通用基本类型,例如基板
  • 可以定义更多专门的元素,从 BasePanel 派生。例如,按钮和文本框。
  • 将存储元素列表(BasePanel 类型,以便可以存储专门的元素)
  • 此列表将遍历每一帧并绘制(暂时忽略优化)

示例用法:

class UIButton : BasePanel
{
    public override void Draw(blah)
    {
        // Specialised drawing code
    }
}

foreach (BasePanel Element in StoredElements)
{
    Element.Draw(blah);
}

这样做的问题是它不会运行专门的代码;它只会运行 BasePanel 代码。 我该如何改进它以便它运行专门的代码?我可以将元素的类型存储在 BasePanel 上,然后在运行时转换为它吗?

我尝试将 BasePanel 存储在存储原始类型的 Container 类中,但我无法访问该方法 - 例如:

foreach(ElementContainer Container in StoredElements)
{
    Type t = Container.OriginalType;
    object el = Container.Element;

    Convert.ChangeType(el, t); //Can't use the returned object!

    t Element = (t)Convert.ChangeType(el, t); //This would be perfect, but it doesn't work.
}

感谢您的帮助。这让我的大脑爆炸了。

【问题讨论】:

  • 你能检查一下 BasePanel.Draw() 是否被标记为虚拟?
  • 我不明白。既然可以只存储派生类型,为什么还要使用 ElementContainer?
  • @Maxim 他只尝试使用容器来解决问题。

标签: c# types polymorphism base


【解决方案1】:

使用以下代码对我来说 100% 有效:

class BasePanel
{
    public virtual void Draw(string blah)
    {
        Console.WriteLine("Base: " + blah);
    }
}

class UIButton : BasePanel
{
    public override void Draw(string blah)
    {
        Console.WriteLine("UIButton: " + blah);
    }
}

class Program
{
    static void Main(string[] args)
    {
        List<BasePanel> list = new List<BasePanel>();

        list.Add(new BasePanel());
        list.Add(new UIButton());
        list.Add(new BasePanel());
        list.Add(new UIButton());
        list.Add(new UIButton());

        foreach (var b in list)
        {
            b.Draw("just a string");
        }
    }
}

你的问题来自你的绘图代码/逻辑。

【讨论】:

  • 完全正确...这应该可以正常工作,并且是存储这些类型和调用方法的正确方法。
  • 谢谢!我没有意识到您可以将派生类型存储在基类型数组中并仍然保留函数等。这是多态性的一部分吗?
  • 是的。任何类型都可以隐式转换为它的 base(而不是相反)。
【解决方案2】:

看起来您的示例应该可以工作,但您可以尝试将 Draw 方法(以及多态性所需的任何其他方法)提取到 Inerface 中,然后在列表中您想要的每个类中实现该接口。

【讨论】:

    【解决方案3】:

    正如 DarkSquirrel 所说,您可以将父类的函数声明为虚拟函数。这应该允许您的代码运行专门的代码

    【讨论】:

    • 谢谢,这个难题的重要组成部分
    【解决方案4】:

    你想执行什么特殊类型

    如果你有

    class Bar {
      public virtual void Draw() {
        DO STUFF!
      } 
    }
    
    class Foo : Bar {
      override public virtual Draw() {
        DO MORE STUFF!
      }
    }
    

    然后在你的代码中的某个地方

    Bar[] data = new Bar[] { new Foo(), new Bar()};
    foreach (Bar elem in data) {
      elem.Draw();
    }
    

    第一个 elem 将为第一个 elem 执行 Foo 中的覆盖代码,为第二个 elem 执行 Bar 中的代码。即使您将一个项目向下转换,方法中执行的代码仍将是原始对象中的代码(并且elem.GetType() 将返回 Foo 为 Foo 类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-22
      • 2023-03-10
      • 2012-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多