具有 2 个相互链接的选项卡和页面泛型类型的选项卡控件类
本文关键字:选项 泛型类型 控件 链接 具有 | 更新日期: 2023-09-27 18:37:24
>我正在尝试为 UI API 提供一个基类来提供 Tab 控件。它在C#.NET(4.5)中,但不使用WinForms。
我让选项卡控件完美运行,但要求在外观和功能上拥有各种自定义选项卡和页面,而不是为每个选项卡和页面克隆大块代码,我正在尝试提供一个通用基类,您为其提供TTab
和TPage
类型。
这个想法是在 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()
约束并修复了该错误。
我想我已经解决了这个问题:
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());
}
}