2012-11-13 35 views
12

Sử dụng .NET 4, tôi bị nhầm lẫn do không có trình biên dịch để giải quyết lời gọi phương thức đầu tiên trong mẫu bên dưới.Vấn đề về độ phân giải phương pháp với thông số mặc định và generics

using System; 

namespace MethodResolutionTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      NonGeneric foo = null; 

      // ambiguous 
      foo.Ext1(x => new NonGeneric()); 

      // resolves to first Ext1 
      foo.Ext1(x => new NonGeneric(), 1); 


      // resolves to first Ext2 
      foo.Ext2(x => new NonGeneric()); 

      // resolves to first Ext2 
      foo.Ext2(x => new NonGeneric(), 1); 

      // resolves to second Ext2 
      foo.Ext2(x => "foo"); 

      // resolves to second Ext2 
      foo.Ext2(x => "foo", 1); 


      // resolves to first Ext3 
      foo.Ext3(x => new NonGeneric()); 

      // resolves to first Ext3 
      foo.Ext3(x => new NonGeneric(), 1); 

      // resolves to second Ext3 
      foo.Ext3(x => "foo"); 

      // resolves to second Ext3 
      foo.Ext3(x => "foo", 1); 
     } 
    } 

    public class NonGeneric 
    { 
    } 

    public class Generic<T> : NonGeneric 
    { 
    } 

    public static class Extensions1 
    { 
     public static NonGeneric Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0) 
     { 
      return null; 
     } 

     public static Generic<TNext> Ext1<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0, string s = null) 
     { 
      return null; 
     } 
    } 

    // only difference between Extensions2 and Extensions1 is that the second overload no longer has a default string parameter 
    public static class Extensions2 
    { 
     public static NonGeneric Ext2(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0) 
     { 
      return null; 
     } 

     public static Generic<TNext> Ext2<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0) 
     { 
      return null; 
     } 
    } 

    // Extensions3 explicitly defines an overload that does not default the int parameter 
    public static class Extensions3 
    { 
     public static NonGeneric Ext3(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext) 
     { 
      return Ext3(first, getNext, default(int)); 
     } 

     public static NonGeneric Ext3(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0) 
     { 
      return null; 
     } 

     public static Generic<TNext> Ext3<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0) 
     { 
      return null; 
     } 
    } 
} 

Có ai có thể làm sáng tỏ điều này không? Tôi nghi ngờ tôi không thực sự có một con đường phía trước ở đây khác hơn là sửa đổi các API của tôi để giúp trình biên dịch (theo Extensions3 ở trên), nhưng nếu có một cách dễ dàng hơn/tốt hơn sau đó tôi rất muốn nghe nó.

Trả lời

1

Không rõ ràng vì bạn có hai tham số tùy chọn trong phương thức mở rộng thứ hai Ext1 thứ hai. Bởi vì cả hai tham số được bỏ qua trong cuộc gọi đầu tiên, trình biên dịch không biết bạn muốn sử dụng thông số nào.

Từ C# 4.0 Language Specification:

§7.5.3 quá tải độ phân giải:

Với các thiết lập của các thành viên chức năng ứng cử viên thích hợp, các thành viên chức năng tốt nhất trong tập hợp đó nằm. Nếu tập hợp chỉ chứa một thành viên chức năng, thì thành viên chức năng đó là thành viên chức năng tốt nhất. Nếu không, thành viên hàm tốt nhất là thành viên hàm tốt nhất so với tất cả các thành viên hàm khác đối với danh sách đối số đã cho, với điều kiện mỗi thành viên hàm được so sánh với tất cả các thành viên hàm khác sử dụng các quy tắc trong §7.5.3.2. Nếu không có chính xác một thành viên hàm nào tốt hơn tất cả các thành viên hàm khác, thì lời gọi hàm thành viên hàm là mơ hồ và xảy ra lỗi liên kết thời gian.

Hơn nữa, theo viên §7.5.3.2 Better chức năng:

thông số bắt buộc không có đối số tương ứng được loại khỏi danh sách tham số

Điều này có nghĩa là khi bạn bỏ qua hai đối số cuối cùng trong cuộc gọi phương thức và loại NonGeneric được phỏng đoán (đọc về suy luận kiểu theo §7.5.2), cả hai phương pháp sẽ trông giống như sau:

Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext) 

Vì thế, họ sẽ là mơ hồ ...

tôi sẽ khuyên bạn nên đọc §7.5.3.2 hoặc thậm chí toàn bộ §7.5.3 của đặc tả để biết thêm.

Giải pháp là một trong hai thay đổi tờ khai phương pháp của bạn hoặc loại bỏ sự quá tải đầu tiên hoàn toàn và để cho thứ hai làm việc :)

+0

Trình biên dịch chọn tốt trong cả 'Extensions2' và' kịch bản Extensions3', vì vậy nó không thật đơn giản. Ngoài ra, nếu tôi không muốn tham số 'int' mặc định, thì rõ ràng tôi sẽ không tuyên bố nó theo cách đó ngay từ đầu! –

+0

Nhưng tại sao bạn có hai phương pháp với các tham số tùy chọn có hiệu quả là mơ hồ nếu các tham số tùy chọn bị bỏ qua? Nếu bạn hoàn toàn cần ** cả hai phương thức, bạn sẽ cần sử dụng các giải pháp 'Extensions2' hoặc' Extensions3'. – khellang

+0

@ khellang: bạn có thể chỉ ra các phần đặc tả ngôn ngữ C# dẫn đến hành vi như vậy (sự mơ hồ về độ phân giải quá tải) không? –

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