2016-02-04 41 views
6

Tôi đang cố gắng tạo danh sách Chế độ xem Biểu mẫu từ một DTO bằng cách gọi một danh sách chọn trong danh sách của DTO. Tuy nhiên, trình biên dịch mang lại cho tôi một câu nói lỗi:Tại sao trình biên dịch không thể suy ra loại cho cuộc gọi chọn này?

Những lập luận kiểu cho phương pháp không thể được suy ra từ việc sử dụng thử xác định các đối số loại

Câu hỏi của tôi là, tại sao không thể nó? Cả hai TextSectionDTOImageSectionDTO có nguồn gốc từ SectionDTO. Tôi đang cố gắng tạo một số List của Sections và cả hai số TextSectionImageSection có nguồn gốc từ Section.

Tôi biết câu hỏi này gần với một số câu hỏi khác được đăng trên đây, nhưng tôi không thể tìm thấy câu trả lời ở đó.

Đây là mã của tôi:

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

Khi tôi thay đổi loại vì vậy mà tôi chỉ chấp nhận SectionDTO lớp cha và chỉ trả lại Mục (Tôi làm cho họ cả hai lớp bình thường trong trường hợp này) các tác phẩm chọn như bạn muốn chờ đợi. Sau đó, khi tôi thay đổi các loại chỉ TextSectionDTO và TextSection (thay đổi các tóm tắt trở lại), lựa chọn không hoạt động nữa.

Tôi muốn một giải pháp để tôi có thể làm việc này với công trình mà tôi có ngay bây giờ, mặc dù tôi quan tâm hơn đến lý do tại sao điều này không hoạt động theo cách đó. Ngay cả khi tôi có thể làm điều này để làm việc tôi có lẽ sẽ refactor này sau này.

Lưu ý:

  • Tôi đang nhắm mục tiêu MVC 4,5 (do đó trình biên dịch không phải là một phiên bản cũ không có khả năng suy luận, đó là giải pháp cho một số câu hỏi tương tự như trên đây).
  • Điều khoản chuyển đổi có trường hợp mặc định, tức là lỗi không được gây ra bởi đường dẫn không trả lại giá trị.

Trả lời

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

Hai trường hợp này trả về các loại khác nhau. Trình biên dịch isn't đủ thông minh để kiểm tra xem những loại có nguồn gốc từ cùng một cơ sở kiểu vì vậy bạn phải quăng explicitely:

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

Tại sao isn't này thực hiện trên trình biên dịch? Tôi cho rằng điều này là do trình biên dịch phải kiểm tra nhiều loại khác nhau. Giả sử rằng hai loại Foo1Foo2 của bạn không trực tiếp xuất phát từ Bar nhưng từ hai loại khác nhau (Bar1Bar2 tương ứng) mà chúng tự kế thừa từ Bar. Bây giờ trình biên dịch nên kiểm tra xem Foo1Foo2 có thể được gán cho bất kỳ lớp cơ sở chung nào mà chúng không thể, và cũng kiểm tra xem chúng có xuất phát từ thứ gì đó có một lớp cơ sở chung (Bar) hay không. Cuối cùng, chúng tôi đã phải kiểm tra toàn bộ chuỗi thừa kế cho đến khi object, không đề cập đến bất kỳ giao diện nào cũng cần được kiểm tra.

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

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

Được rồi, đây làm việc, dán 'như mục' đằng sau cả lợi nhuận. Tại sao tôi cần phải làm điều này mặc dù? Không phải là một thực tế rằng cả hai đều lấy được từ phần là đủ cho thực tế là tôi đang trở về một danh sách các phần trong phương pháp biểu thức là trong? – Glubus

+1

Tôi cho rằng điều này là bởi vì nếu trình biên dịch WOULD kiểm tra toàn bộ chuỗi thừa kế, điều này có thể mất vài vòng trên toàn bộ chuỗi. Như bạn đang có một chuỗi sâu hơn nhiều. Bây giờ trình biên dịch nên kiểm tra tất cả các giao diện và các lớp cơ sở được đề cập trong toàn bộ chuỗi có thể mất quá nhiều thời gian. – HimBromBeere

+1

Cả hai đều được kế thừa từ 'đối tượng'. –

3

Select phương pháp có hai loại aguments - TSourceTResult.Vì bạn đang gọi nó trên IEnumerable<SectionDTO>, TSource được phỏng đoán là SectionDTO, do đó, ss.Select((SectionDTO s) => là không cần thiết và có thể chỉ là ss.Select(s => ....

Sự cố là TResult mà trong trường hợp của bạn không thể suy ra được. Tại sao? Bạn có hai lợi tức - TextSectionImageSection. Họ không giống nhau và không ai trong số họ là cơ sở của người khác. Bạn nghĩ trình biên dịch sẽ suy luận ra sao? Bạn nghĩ rằng câu trả lời phải là loại cơ sở chung Section, nhưng cùng có thể áp dụng cho một cơ sở chung object hoặc bất kỳ lớp cơ sở/giao diện chung nào của hai loại. Nói cách khác, kết quả là mơ hồ, vì vậy thay vì đoán ý định của bạn là gì, trình biên dịch yêu cầu bạn chỉ định rõ ràng. Tương tự như nhà điều hành ternary ? : nó sẽ là đủ để xác định các cơ sở chung trong chỉ là một chi nhánh, vì vậy sau đây sẽ giải quyết nó

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

Giải thích này rất hữu ích, tôi hiểu nó ngay bây giờ. Cảm ơn. – Glubus

Các vấn đề liên quan