2012-09-06 2 views
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 в виде ряда таблиц. Чтобы разделить мои проблемы, я создал formatters, которые будут потреблять группы и выделять необходимую разметку. Используя фабрику, я выберу соответствующий форматировщик:

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 ». Затем я попытался создать неявный оператор, чтобы преобразования могли быть между поточная линия и TissueProductionLine, но вы не можете сделать это с помощью базовых и производных типов.

Если кто-то может пролить свет на это, я оценил бы имея мое любопытство удовлетворено! Спасибо!

Chris

+0

Почему не может '' TissueProductionLineGroupFormatter продлить 'ProductionLineGroupFormatter ', и если это форматтер для этого конкретного типа, то каково общее ограничение типа 'T' для? – mellamokb

+0

Если удалить ограничение, то я получаю ошибку в моей фабрике: Не может неявно преобразовать тип «TissueProductionLineGroupFormatter» до «ProductionLineGroupFormatter » –

ответ

3

Вы должны быть в состоянии:

public class TissueProductionLineGroupFormatter : 
    ProductionLineGroupFormatter<TissueProductionLine> { 
    ... 
} 

UPDATE

Для завода, вы могли бы реализовать конкретные методы типа вместо использования условной логики для проверки типов:

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.... 
} 
+0

Пробовал, но потом я обновить мою фабрику к этому: 'общественный статический класс ProductionLineGroupFormatterFactory где Т: поточная линия { общественности статической ProductionLineGroupFormatter GetProductionLineGroupFormatter (ProductionLineGroup группа) { , если (TypeOf (Т) == TypeOf (TissueProductionLineGroup)) { вернуть новый TissueProduc tionLineGroupFormatter(); } } } ' Тогда я получаю ошибку Не удается неявно преобразовать тип 'TissueProductionLineGroupFormatter' в«ProductionLineGroupFormatter

+0

@ChrisHardie: добавил идею для этого .... –

1

Если вы создадите классы для реализации этого интерфейса и верните фабрику IProductionLineGroupFormatter<T>, это должно работать.

public interface IProductionLineGroupFormatter<out T> where T : ProductionLine 
{ 
    public string Name { get; set; } 
    public IEnumerable<T> ProductionLines { get; set; } 
} 

И как решение Jordao в:

public class TissueProductionLineGroupFormatter : 
    ProductionLineGroupFormatter<TissueProductionLine>, IProductionLineGroupFormatter<TissueProductionLine> { 
    ... 
} 
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>"); 
    } 
} 
Смежные вопросы