2016-02-04 1 views
6

Я пытаюсь создать список ViewModels из DTO, вызывая выбор в списке DTO. Однако компилятор дает мне поговорку об ошибке:Почему компилятор не может указать тип этого выбора?

Аргументы типа для метода не может быть выведено из эксплуатации попробуйте указать аргументы типа

мой вопрос, почему не может? Оба TextSectionDTO и ImageSectionDTO получены из SectionDTO. Я пытаюсь создать ListSections, и оба TextSection и ImageSection получены из Section.

Я знаю, что этот вопрос близок к некоторым другим вопросам, размещенным здесь, но я не смог найти там ответа.

Это мой код:

private List<Section> BuildSectionViewModel(IEnumerable<SectionDTO> ss) 
{ 
    var viewModels = ss.Select((SectionDTO s) => 
    { 
     switch (s.SectionType) 
     { 
      case Enums.SectionTypes.OnlyText: 
       return new TextSection((TextSectionDTO) s); 
      case Enums.SectionTypes.OnlyImage: 
       return new ImageSection((ImageSectionDTO) s); 
      default: 
       throw new Exception("This section does not exist - FIXME"); 
     } 
    }).ToList(); 

    return viewModels; 
} 

Когда я изменить типы, так что я только принимаю суперкласса SectionDTO и возвращать только раздел (я делаю их как обычные классы в этом сценарии), что выберите работает как вы хотите ожидать. Затем, когда я меняю типы только на TextSectionDTO и TextSection (меняя тезисы назад), выбор больше не работает.

Я бы хотел, чтобы это помогло мне работать со строительством, которое у меня есть сейчас, хотя меня больше интересует, почему это не работает так, как есть. Даже если я смогу заставить это работать, я, вероятно, реорганизую это позже.

Примечание:

  • Я нацеливание MVC 4.5 (так что компилятор не какая-то старая версия не в состоянии сделать вывод, что было решение некоторых подобных вопросов здесь).
  • Предложение switch имеет случай по умолчанию, то есть ошибка не может быть вызвана путем, не возвращающим значение.

ответ

6
case Enums.SectionTypes.OnlyText: 
    return new TextSection((TextSectionDTO) s); 
case Enums.SectionTypes.OnlyImage: 
    return new ImageSection((ImageSectionDTO) s); 

Эти два случая возврата диффере типов. Компилятор не правда достаточно умны, чтобы проверить, если эти типы проистекают из того же базового типа, так что вы должны бросить их явно:

case Enums.SectionTypes.OnlyText: 
    return (SectionDTO) new TextSection((TextSectionDTO) s); 
case Enums.SectionTypes.OnlyImage: 
    return (SectionDTO) new ImageSection((ImageSectionDTO) s); 

Почему это не правда реализована на компилятор? Я предполагаю, что это связано с тем, что компилятор должен проверять разные типы. Предположим, что ваши два типа Foo1 и Foo2 напрямую не связаны с Bar, но из двух разных (Bar1 и Bar2 соответственно), что они наследуют от Bar. Теперь компилятор должен проверить, могут ли Foo1 и Foo2 присвоить любой общий базовый класс, который они не могут, а также проверить, получают ли они что-то, что имеет общий базовый класс (Bar). В итоге нам пришлось проверять всю цепочку наследования до object, не говоря уже о каких-либо интерфейсах, которые также должны быть проверены.

class Foo1 : Bar1 {} 
class Foo2 : Bar2 {} 

class Bar1 : Bar {} 
class Bar2 : Bar {} 
+0

Хорошо, это работало, вставили «в разделе» позади оба деклараций. Зачем мне это нужно? Разве не должно быть факта, что они оба выводятся из Секции, достаточно, учитывая тот факт, что я возвращаю список разделов в методе, в котором находится выражение? – Glubus

+1

Я полагаю, это связано с тем, что если компилятор должен проверить всю цепочку наследования, это может занять несколько циклов на всей цепочке. Assuem у вас будет гораздо более глубокая цепь. Теперь компилятор должен проверять все интерфейсы и базовые классы, упомянутые во всей цепочке, которые могут занять слишком много времени. – HimBromBeere

+1

Оба они также наследуются от 'object'. –

3

Select метод имеет два типа aguments - TSource и TResult.Поскольку вы вызываете его на IEnumerable<SectionDTO>, TSource считается SectionDTO, поэтому ss.Select((SectionDTO s) => не нужен и может быть только ss.Select(s => ....

Проблема TResult, которая в вашем случае не может быть выведена. Зачем? У вас есть два возвращения - TextSection и ImageSection. Они не одно и то же, и никто из них не является базой другого. Как вы думаете, компилятор должен сделать вывод? Вы считаете, что ответ должен быть общим базовым типом Section, но то же самое можно было бы применить к общей базе object или к любому обычному базовому классу/интерфейсу двух типов. Другими словами, результат неоднозначен, поэтому вместо того, чтобы угадать, каково ваше намерение, компилятор требует, чтобы вы указали это явно. Подобно троичный оператор ? : было бы достаточно, чтобы определить общую базу только в одной отрасли, так что следующие должны решить его

var viewModels = ss.Select(s => 
{ 
    switch (s.SectionType) 
    { 
     case Enums.SectionTypes.OnlyText: 
      return (Section)new TextSection((TextSectionDTO) s); 
     case Enums.SectionTypes.OnlyImage: 
      return new ImageSection((ImageSectionDTO) s); 
     default: 
      throw new Exception("This section does not exist - FIXME"); 
    } 
}).ToList(); 
+0

Это объяснение очень полезно, я понимаю это сейчас. Благодарю. – Glubus

Смежные вопросы