具有 2 个相互链接的选项卡和页面泛型类型的选项卡控件类

本文关键字:选项 泛型类型 控件 链接 具有 | 更新日期: 2023-09-27 18:37:24

>我正在尝试为 UI API 提供一个基类来提供 Tab 控件。它在C#.NET(4.5)中,但不使用WinForms。

让选项卡控件完美运行,但要求在外观和功能上拥有各种自定义选项卡和页面,而不是为每个选项卡和页面克隆大块代码,我正在尝试提供一个通用基类,您为其提供TTabTPage类型。

这个想法是在 API 中,然后我可以提供类,这些类简单地将泛型基础包装成一个非泛型类来实际使用:DefaultTabs : BaseTabs<DefaultTab, DefaultTabPage>

没想到这会特别麻烦,但一路上我设法弄糊涂了,而且我很确定我开始对这个问题不加代码盲。

这是一个归结的版本:

namespace ExtendTabs.soExample
{
    using System.Collections.Generic;
    public class Example<TTab, TPage>
        where TTab : Tab<TPage>, new()
        where TPage : TabPage<TTab>, new()
    {
        private List<TTab> tabs;
        public Example()
        {
            this.tabs = new List<TTab>();
            this.tabs.Add(new TTab());
        }
    }
    public class Tab<TPage>
        where TPage : new()  //  where TPage : TabPage<..? All I can think of is "TabPage<Tab<TPage>>" and that seems very wrong.
    {
        public Tab()
        {
            this.Page = new TPage(); // Can't pass this in because of the where new() constraint.
            //this.Page.Tab = this;  // Can't do this because TPage does not contain where
            //this.Page.Link(this);  // Can't do this because TPage does not contain where
        }
        public TPage Page { get; private set; }
    }
    public class TabPage<TTab>
    {
        public TabPage() // Can't take in Tab<TPage> here because of type problems and new() constrain used.
        {
        }
        public TTab Tab { get; internal set; }
        internal void Link(TTab tab)
        {
            this.Tab = tab;
        }
    }
}

2个主要问题是:

  • 它不会在主类行上编译,带有'TPage' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TPage' in the generic type or method 'ExtendTabs.soExample.Tab<TPage>'.我不理解这个错误,因为 TPage 确实有一个公共的无参数构造函数并且是非抽象的。(谢谢西瓦)

  • 我似乎无法将TTab实例添加到TPage实例中,而不会以某种递归泛型类型地狱告终。

我希望我已经看了太久了,并试图让这个问题变得太复杂了。看起来应该比这容易得多。有什么建议吗?


第一个问题源于主类不包含与子类相同的泛型约束。根据 Siva提供的链接,我现在已经添加了new()约束并修复了该错误。

具有 2 个相互链接的选项卡和页面泛型类型的选项卡控件类

我想我已经解决了这个问题:

namespace WindowsFormsApplication1.soExample
{
    using System.Collections.Generic;
    public abstract class BaseTabs<TTab, TPage>
        where TTab : BaseTabsTab<TTab, TPage>, new()
        where TPage : BaseTabsTabPage<TTab, TPage>, new()
    {
        private List<TTab> tabs;
        public BaseTabs()
        {
            this.tabs = new List<TTab>();
        }
        public IEnumerable<TPage> Pages
        {
            get
            {
                foreach (TTab tab in this.Tabs)
                {
                    yield return tab.Page;
                }
            }
        }
        public IEnumerable<TTab> Tabs { get { return this.tabs; } }
        public TTab Add()
        {
            TTab tab = new TTab();
            this.tabs.Add(tab);
            return tab;
        }
    }
    public abstract class BaseTabsTab<TTab, TPage>
        where TTab : BaseTabsTab<TTab, TPage>, new()
        where TPage : BaseTabsTabPage<TTab, TPage>, new()
    {
        public BaseTabsTab()
        {
            this.Page = new TPage();
            this.Page.Tab = (TTab)this;
        }
        public TPage Page { get; private set; }
    }
    public abstract class BaseTabsTabPage<TTab, TPage>
        where TTab : BaseTabsTab<TTab, TPage>, new()
        where TPage : BaseTabsTabPage<TTab, TPage>, new()
    {
        public BaseTabsTabPage()
        {
        }
        public TTab Tab { get; internal set; }
    }
    public class DefaultTab : BaseTabsTab<DefaultTab, DefaultTabPage> { }
    public class DefaultTabPage : BaseTabsTabPage<DefaultTab, DefaultTabPage> { }
    public class DefaultTabs : BaseTabs<DefaultTab, DefaultTabPage> { }
}

这为选项卡和页面提供了强类型支持,并允许创建具有扩展选项卡或页面的新选项卡。3 个默认类允许您使用它,而无需参与不需要的混乱泛型减速:

DefaultTabs tabs = new DefaultTabs();
tabs.Add();
foreach (DefaultTab tab in tabs.Tabs) { }
foreach (DefaultTabPage page in tabs.Pages) { }

现在也应该清楚从选项卡或页面链接回主选项卡容器。

只是想我会发布解决方案,以防其他人遇到类似的鸡和蛋泛型问题。

基于此 SO 帖子,您可以将示例类更改为:

public class Example<TTab, TPage>  // 'TPage' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TPage' in the generic type or method 'ExtendTabs.soExample.Tab<TPage>'
        where TTab : Tab<TPage>, new() 
        where TPage : TabPage<TTab>, new() //new() is provided here as a means to indicate constraint
    {
        private List<TTab> tabs;
        public Example()
        {
            this.tabs = new List<TTab>();
            this.tabs.Add(new TTab());
        }
    }