2016-02-04 7 views
6

私は、DTOのリストからselectを呼び出すことによって、DTOからViewModelsのリストを作成しようとしています。メソッドのコンパイラがこの選択呼び出しの型を推論できないのはなぜですか?

型引数は、使用状況から推測することはできません

私の質問は、なぜそれできない、ある型引数を指定してみてください: はしかし、コンパイラは私に言ってエラーになりますか? TextSectionDTOImageSectionDTOの両方はSectionDTOに由来します。 ListSectionsに作成しようとしており、TextSectionImageSectionの両方がSectionに由来しています。

私はこの質問がここに掲載されている他の質問に近いことは知っていますが、回答が見つかりませんでした。

これは私のコードです:

私は唯一のスーパーSectionDTOを受け入れ、唯一のセクション(私はそれらをこのシナリオでは、通常のクラスの両方にする)あなたのような選択な作品と思いを返すように、私は種類を変更
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; 
} 

期待する。次に、タイプを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); 

これらの2つのケースがdifferenタイプを返します。これらのタイプは、同じ基本型から派生する場合は、明示的にそれらをキャストする必要がありますので十分にスマートisn'tコンパイラがチェックする:このisn'tは、コンパイラに実装なぜ

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

?これは、コンパイラが多くの異なる型をチェックする必要があるためです。 Foo1Foo2の2種類がBarから直接派生するのではなく、Barから継承する2つの異なる種類(Bar1Bar2に応じて)から直接得られると仮定します。コンパイラはFoo1Foo2が共通の基底クラスに割り当てられていないかどうかをチェックし、共通基本クラス(Bar)を持つものから派生しているかどうかをチェックする必要があります。最後に、objectまで継承チェーン全体をチェックしなければなりませんでした。チェックする必要があるインターフェースについては言及していませんでした。 TSourceTResult -

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

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

を解決する必要があります。なぜ私はこれを行う必要がありますか?彼らは両方のセクションから派生しているという事実は、私は式がである方法のセクション一覧を返していたという事実与え十分ではありませんか。 – Glubus

+1

私は、コンパイラが全体の継承チェーンをチェックするならば、これは全体のチェーンに複数のループがかかる場合がありますので、これはあると仮定します。あなたがもっと深い鎖を持っていると仮定してください。コンパイラは、チェーン全体で言及されているすべてのインタフェースとベースクラスに対して、時間がかかりすぎるかどうかをチェックする必要があります。 – HimBromBeere

+1

これらは両方とも 'object'から継承します。 '新しい[] {A、B、C}': –

3

Select方法は、2つのタイプagumentsを有しています。あなたはIEnumerable<SectionDTO>でそれを呼び出しているので、TSourceSectionDTOと推定されるので、ss.Select((SectionDTO s) =>は必要ありませんし、ちょうどss.Select(s => ...することができます。

問題は、あなたの場合には推測できないTResultです。どうして?返品はTextSectionImageSectionです。彼らは同じではなく、他のものの基盤ではありません。コンパイラは何を推論するべきだと思いますか?あなたは答えは、共通の基本型Sectionであるべきだと思いますが、同じことは、共通のベースobjectまたは2種類のいずれかの共通の基底クラス/インタフェースに適用することができます。言い換えれば、結果はあいまいなので、あなたの意図が何であるかを推測するのではなく、明示的に指定する必要があります。三項演算子? :と同様に、ただ一つの枝に共通のベースを指定するのに十分であるので、以下では、両方のリターンの後ろに「セクションとして」貼り付け、これは働いていた、オーケー、それを

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

関連する問題