C# 试图避免我的泛型转换
我建立了一个严重依赖泛型的体系结构。在某一点上,我必须转换为基本类型,出于好奇,我想知道我是否可以避开它 背景是我们有一些生产线组,我们希望打印到一个网页。由于每个组的生产线都有一些相同的信息,但也有一些不同的信息,因此我使用了一个抽象类:C# 试图避免我的泛型转换,c#,.net,generics,C#,.net,Generics,我建立了一个严重依赖泛型的体系结构。在某一点上,我必须转换为基本类型,出于好奇,我想知道我是否可以避开它 背景是我们有一些生产线组,我们希望打印到一个网页。由于每个组的生产线都有一些相同的信息,但也有一些不同的信息,因此我使用了一个抽象类: public abstract class ProductionLine { public int LineNumber { get; set; } public string Name { get; set; } public do
public abstract class ProductionLine
{
public int LineNumber { get; set; }
public string Name { get; set; }
public double Target { get; set; }
public double Actual { get; set; }
public double Variance { get; set; }
}
下面是一个具体实施的示例:
public class TissueProductionLine : ProductionLine
{
public double Budget { get; set; }
public double PercentOnTarget { get; set; }
}
因为我们讨论的是生产线的组,所以我创建了一个抽象对象来存放组及其所有生产线的名称:
public abstract class ProductionLineGroup<T> where T : ProductionLine
{
public string Name { get; set; }
public List<T> ProductionLines { get; set; }
}
下面是一个组的具体实现:
public class TissueProductionLineGroup : ProductionLineGroup<TissueProductionLine>
{
public string TissueType { get; set; }
}
一切都很好,但我希望能够将生产线组作为一系列表呈现为HTML。为了分离我的顾虑,我创建了格式化程序,这些格式化程序将使用组并发出所需的标记。使用工厂,我将选择适当的格式化程序:
public static class ProductionLineGroupFormatterFactory<T> where T : ProductionLine
{
public static ProductionLineGroupFormatter<T> GetProductionLineGroupFormatter(ProductionLineGroup<T> group)
{
if (typeof(T) == typeof(TissueProductionLineGroup))
{
return new TissueProductionLineGroupFormatter<T>();
}
throw new ApplicationException("Could not find an appropriate formatter for this Production Line type:" + typeof(T).ToString());
}
}
factory方法返回一个基本类型为ProductionLineGroupFormatter的对象:
public abstract class ProductionLineGroupFormatter<T> where T : ProductionLine
{
public abstract string Render(ProductionLineGroup<T> group);
}
public class TissueProductionLineGroupFormatter<T> : ProductionLineGroupFormatter<T> where T : ProductionLine
{
public override string Render(ProductionLineGroup<T> group)
{
foreach (ProductionLine line in group.ProductionLines)
{
TissueProductionLine tLine = (TissueProductionLine)line;
sb.Append(@"<tr>
<td>" + tLine.Name + @"</td>
<td>" + tLine.Actual + @"</td>
<td>" + tLine.Target + @"</td>
<td>" + tLine.Variance + @"</td>
<td>" + tLine.PercentOnTarget + @"</td>
</tr>");
}
}
return sb.ToString();
}
}
实际执行渲染的派生类型是TissueProductionLineGroupFormatter:
public abstract class ProductionLineGroupFormatter<T> where T : ProductionLine
{
public abstract string Render(ProductionLineGroup<T> group);
}
public class TissueProductionLineGroupFormatter<T> : ProductionLineGroupFormatter<T> where T : ProductionLine
{
public override string Render(ProductionLineGroup<T> group)
{
foreach (ProductionLine line in group.ProductionLines)
{
TissueProductionLine tLine = (TissueProductionLine)line;
sb.Append(@"<tr>
<td>" + tLine.Name + @"</td>
<td>" + tLine.Actual + @"</td>
<td>" + tLine.Target + @"</td>
<td>" + tLine.Variance + @"</td>
<td>" + tLine.PercentOnTarget + @"</td>
</tr>");
}
}
return sb.ToString();
}
}
注意我需要在foreach循环中进行的转换。我不知道是否有可能避免它。我最初试图将T约束到TissueProductionLine,因为它是从ProductionLine派生的,但我得到一个错误,即没有从“T”到“TissueProductionLine”的隐式引用转换。然后,我尝试创建一个隐式运算符,以便可以在ProductionLine和TissueProductionLine之间进行转换,但不能使用基类型和派生类型进行转换
如果有人能解释这一点,我希望我的好奇心得到满足!谢谢
克里斯你应该能够做到这一点:
public class TissueProductionLineGroupFormatter :
ProductionLineGroupFormatter<TissueProductionLine> {
...
}
更新
对于工厂,您可以实现特定于类型的方法,而不是使用条件逻辑来测试类型:
public static class ProductionLineGroupFormatterFactory {
public static ProductionLineGroupFormatter<TissueProductionLine> GetProductionLineGroupFormatter(ProductionLineGroup<TissueProductionLine> group) {
return new TissueProductionLineGroupFormatter();
}
// .. other factory methods....
}
也许您可以创建更好的命名方法,这样就不需要参数:
public static class ProductionLineGroupFormatterFactory {
public static ProductionLineGroupFormatter<TissueProductionLine> GetTissueProductionLineGroupFormatter() {
return new TissueProductionLineGroupFormatter();
}
// .. other factory methods....
}
您应该能够做到这一点:
public class TissueProductionLineGroupFormatter :
ProductionLineGroupFormatter<TissueProductionLine> {
...
}
更新
对于工厂,您可以实现特定于类型的方法,而不是使用条件逻辑来测试类型:
public static class ProductionLineGroupFormatterFactory {
public static ProductionLineGroupFormatter<TissueProductionLine> GetProductionLineGroupFormatter(ProductionLineGroup<TissueProductionLine> group) {
return new TissueProductionLineGroupFormatter();
}
// .. other factory methods....
}
也许您可以创建更好的命名方法,这样就不需要参数:
public static class ProductionLineGroupFormatterFactory {
public static ProductionLineGroupFormatter<TissueProductionLine> GetTissueProductionLineGroupFormatter() {
return new TissueProductionLineGroupFormatter();
}
// .. other factory methods....
}
如果让类实现此接口,并让工厂返回IPProductionLineGroupFormatter,则应该可以这样做
public interface IProductionLineGroupFormatter<out T> where T : ProductionLine
{
public string Name { get; set; }
public IEnumerable<T> ProductionLines { get; set; }
}
就像Jordão的解决方案一样:
public class TissueProductionLineGroupFormatter :
ProductionLineGroupFormatter<TissueProductionLine>, IProductionLineGroupFormatter<TissueProductionLine> {
...
}
如果让类实现此接口,并让工厂返回IPProductionLineGroupFormatter,则应该可以这样做
public interface IProductionLineGroupFormatter<out T> where T : ProductionLine
{
public string Name { get; set; }
public IEnumerable<T> ProductionLines { get; set; }
}
就像Jordão的解决方案一样:
public class TissueProductionLineGroupFormatter :
ProductionLineGroupFormatter<TissueProductionLine>, IProductionLineGroupFormatter<TissueProductionLine> {
...
}
我会这样做:
public abstract class ProductionLineGroupFormatter<T> where T : ProductionLine
{
public string Render(ProductionLineGroup<T> group)
{
foreach (T line in group.ProductionLines)
{
AppendProductionLine(line);
}
return sb.ToString();
}
protected abstract void AppendProductionLine(T line);
}
public class TissueProductionLineGroupFormatter : ProductionLineGroupFormatter<TissueProductionLine>
{
protected override void AppendProductionLine(TissueProductionLine line)
{
sb.Append(@"<tr>
<td>" + line.Name + @"</td>
<td>" + line.Actual + @"</td>
<td>" + line.Target + @"</td>
<td>" + line.Variance + @"</td>
<td>" + line.PercentOnTarget + @"</td>
</tr>");
}
}
我会这样做:
public abstract class ProductionLineGroupFormatter<T> where T : ProductionLine
{
public string Render(ProductionLineGroup<T> group)
{
foreach (T line in group.ProductionLines)
{
AppendProductionLine(line);
}
return sb.ToString();
}
protected abstract void AppendProductionLine(T line);
}
public class TissueProductionLineGroupFormatter : ProductionLineGroupFormatter<TissueProductionLine>
{
protected override void AppendProductionLine(TissueProductionLine line)
{
sb.Append(@"<tr>
<td>" + line.Name + @"</td>
<td>" + line.Actual + @"</td>
<td>" + line.Target + @"</td>
<td>" + line.Variance + @"</td>
<td>" + line.PercentOnTarget + @"</td>
</tr>");
}
}
为什么TissueProductionLineGroupFormatter不能扩展ProductionLineGroupFormatter,如果它是该特定类型的格式化程序,那么泛型t类型约束是什么?如果我删除该约束,然后,我在工厂中遇到一个错误:无法将类型“TissueProductionLineGroupFormatter”隐式转换为“ProductionLineGroupFormatter”。为什么TissueProductionLineGroupFormatter不能扩展ProductionLineGroupFormatter,如果它是该特定类型的格式化程序,那么泛型t类型约束是什么?如果我删除该约束,然后我在我的工厂中遇到一个错误:无法将类型“TissueProductionLineGroupFormatter”隐式转换为“ProductionLineGroupFormatter”,我尝试了此操作,但随后我将工厂更新为:公共静态类ProductionLineGroupFormatterFactory,其中T:ProductionLine{公共静态ProductionLineGroupFormatter GetProductionLineGroupFormatterProductionLineGroup组{如果typeofT==typeofTissueProductionLineGroup{返回新的组织ProductionLineGroupFormatter;}}}}然后我得到一个错误,无法将类型“TissueProductionLineGroupFormatter”隐式转换为“ProductionLineGroupFormatter”。我尝试了这一点,但随后我将工厂更新为:公共静态类ProductionLineGroupFormatterFactory,其中T:ProductionLine{公共静态ProductionLineGroupFormatter GetProductionLineGroupFormatterProductionLineGroup组{如果typeofT==typeofTissueProductionLineGroup{返回新的组织ProductionLineGroupFormatter;}}}}然后,我发现错误,无法将类型“TissueProductionLineGroupFormatter”隐式转换为“ProductionLineGroupFormatter”