我正在尝试为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;
}
}
}
两个主要问题是:
它不会在主类行上使用(谢谢Siva)'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()
约束并修复了该错误。
答案 0 :(得分:1)
我想我现在已经解决了这个问题:
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) { }
现在也应该清楚地从标签页或页面链接回主标签容器。
只是想我发布解决方案,以防其他人遇到类似鸡肉和鸡蛋仿制品的问题。
答案 1 :(得分:0)
根据此SO Post,您可以将Example类更改为:
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());
}
}