我正在使用C#数据可视化库,它大量使用泛型。我们的应用程序需要以编程方式构建这些图表,包括在运行时更改图表系列。代码如下所示:
builder.Series(series =>
{
if (seriesDefinition.Type == ChartType.Bar) {
series.Bar(data).Name(seriesDefinition.Name);
}
else if (seriesDefinition.Type == ChartType.Area) {
series.Area(data).Name(seriesDefinition.Name);
}
})
Bar()
和Area()
调用是库方法,seriesDefinition
对象是我们自己的类,其中包含有关我们要创建的系列的配置信息。
现在,我们的系列定义对象除了名称之外还将具有许多属性,并且所有这些属性都需要应用于构建器中的系列。为避免大量代码重复,我们希望存储Bar()
或Area()
等调用的结果,以便我们可以在if-else块之外应用其余配置。为此,我们需要声明其特定类型。从这些库方法的派生返回类型向后工作,我们得到了这个父类型,它具有我们需要的方法:
public abstract class ChartSeriesBuilderBase<TSeries, TSeriesBuilder> : IHideObjectMembers
where TSeries : IChartSeries
where TSeriesBuilder : ChartSeriesBuilderBase<TSeries, TSeriesBuilder>
{
}
现在我需要用适当的类型参数声明它:
builder.Series(series =>
{
ChartSeriesBuilderBase<IChartSeries, ???> seriesBuilder = null; // <--
if (seriesDefinition.Type == ChartType.Bar) {
seriesBuilder = series.Bar(data);
}
else if (seriesDefinition.Type == ChartType.Area) {
seriesBuilder = series.Area(data);
}
seriesBuilder.Name(seriesDefinition.Name);
})
我可以用???
替换满足此类型声明的内容吗?
编辑:以下是以Bar()
或Area()
的返回类型开头的类层次结构。
// Area() returns this; Bar() returns ChartBarSeriesBuilder
public class ChartAreaSeriesBuilder<T> :
ChartAreaSeriesBuilderBase<IChartAreaSeries, ChartAreaSeriesBuilder<T>>
where T : class
{
}
T
是该系列的数据项的类型,我可以控制。当我将该类型的对象传递给Area()
时,推断出它。
// or ChartBarSeriesBuilderBase
public abstract class ChartAreaSeriesBuilderBase<TSeries, TSeriesBuilder> :
ChartSeriesBuilderBase<TSeries, TSeriesBuilder>
where TSeries : IAreaSeries
where TSeriesBuilder : ChartAreaSeriesBuilderBase<TSeries, TSeriesBuilder>
{
}
最后
public abstract class ChartSeriesBuilderBase<TSeries, TSeriesBuilder> : IHideObjectMembers
where TSeries : IChartSeries
where TSeriesBuilder : ChartSeriesBuilderBase<TSeries, TSeriesBuilder>
{
}
答案 0 :(得分:1)
tl; dr 除非ChartSeriesBuilderBase
实现其他一些非通用接口,否则不能这样做。
您可以创建一个继承自ChartSeriesBuilderBase
的类,然后对其进行实例化,这样可行,如下所示:
public class MyBuilder : ChartSeriesBuilderBase<IChartSeries, MyBuilder>
{
}
它有点令人困惑,但是在定义MyBuilder
时,它能够将自身引用为其基类的泛型类型。
我认为Bar
和Area
也以类似的方式定义,因此在它们自己的通用定义中引用它们。当Bar
和Area
继承自ChartSeriesBuilderBase
时,我们可以声明以下变量:
ChartSeriesBuilderBase<IChartSeries, Bar> myBarBuilder;
ChartSeriesBuilderBase<IChartSeries, Area> myAreaBuilder;
但同样,由于这些变量被输入Bar
或Area
,因此它们无法帮助我们创建能够包含两种对象类型的变量。
现在考虑一下类似但简化的情况:
public class MyGeneric<T>
{
}
void q49156521()
{
var myObject = new MyGeneric<string>();
var myOtherObject = new MyGeneric<int>();
}
虽然两个变量都是MyGeneric
,但我没有可用于定义变量的基类,它可以同时包含myObject
和myOtherObject
,因为它们的区别在于通用类型。
请注意,许多泛型类允许您通过实现非泛型接口来解决此确切问题。例如,List<T>
实施IList
,因此可以使用IList
变量同时包含List<string>
和List<int>
。但是,看起来ChartSeriesBuilderBase
没有可以使用的界面。
所以我担心看起来答案是,你不能。
我不得不在这里引用另一个问题甚至知道这是一件事:https://stackoverflow.com/a/25166761/8915494
希望这有帮助