2

我有一个严重依赖泛型的架构设置。在某一时刻,我确实必须转换为基本类型,出于好奇,我想知道我是否可以回避它。

背景是我们有许多想要打印到网页的生产线组。由于每个组的生产线有一些相同的信息,但也有一些不同的信息,我使用了一个抽象类:

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());
    }
}

工厂方法返回一个基类型为 ProductionLineGroupFormatter 的对象:

public abstract class ProductionLineGroupFormatter<T> where T : ProductionLine
{
    public abstract string Render(ProductionLineGroup<T> group);
}

实际进行渲染的派生类型是 TissueProductionLineGroupFormatter:

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 之间创建,但您不能对基本类型和派生类型执行此操作。

如果有人能对此有所了解,我将不胜感激满足我的好奇心!谢谢!

克里斯

4

3 回答 3

3

你应该能够做到这一点:

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....
}
于 2012-09-06T18:20:20.670 回答
1

如果你让你的类实现这个接口,并让你的工厂返回一个IProductionLineGroupFormatter<T>,这应该可以工作。

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> {
  ...
}
于 2012-09-06T19:12:56.023 回答
0

我会这样做:

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>"); 
    } 
} 
于 2012-09-11T18:42:34.607 回答