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”