2011-01-05 15 views
6

Possible Duplicate:
Why is Func<T> ambiguous with Func<IEnumerable<T>>?Generics, độ phân giải quá tải và các đại biểu (xin lỗi, không thể tìm thấy một tiêu đề tốt hơn)

tôi nhận thấy một nghị quyết tình trạng quá tải vấn đề rất lạ với Generics ...

Xem xét các phương pháp sau:

static void Foo<TSource>(TSource element, Func<TSource, int> selector) 
{ 
    "int".Dump(); 
} 

static void Foo<TSource>(TSource element, Func<TSource, double> selector) 
{ 
    "double".Dump(); 
} 

static T Identity<T>(T value) 
{ 
    return value; 
} 

(C# 4, thử nghiệm trong LINQPad)

Nếu tôi cố gắng gọi Foo với một biểu thức lambda như bộ chọn , Mọi thứ hoạt động tốt:

Foo(42, x => x); // prints "int" 

Nhưng nếu tôi thay x => x với Identity, trình biên dịch không thể quyết định giữa 2 Foo quá tải:

Foo(42, Identity); 
// The call is ambiguous between the following methods or properties: 
// 'UserQuery.Foo<int>(int, System.Func<int,int>)' and 
// 'UserQuery.Foo<int>(int, System.Func<int,double>)' 

Làm thế nào sự quá tải thứ hai có thể là một ứng cử viên hợp lệ? Loại suy luận xác định một cách chính xác rằng TSourceint, vì vậy tham số T cho phương pháp Identity phải là int là tốt, vì vậy các kiểu trả về phải là int quá ... Identity có thể là một Func<int,int> hoặc một Func<double,double>, nhưng không phải là một Func<int,double>!

Và nó trở nên tồi tệ hơn! Ngay cả khi tôi chỉ định tất cả các thông số loại một cách rõ ràng, tôi vẫn nhận được cùng một lỗi:

Foo<int>(42, Identity<int>); // The call is ambiguous... 

Làm cách nào có thể có sự mơ hồ ở đây? Theo như tôi có thể nói, không có cách nào sự quá tải mất Func<int,double> có thể là một ứng cử viên. Tôi đoán lời giải thích phải ở đâu đó trong các chi tiết kỹ thuật, nhưng tôi không thể tìm thấy bit có liên quan ... hoặc nó có thể là một lỗi trong trình biên dịch, nhưng tôi đoán nó không chắc.

Lưu ý rằng nó không làm việc nếu tôi dứt khoát tạo ra các đại biểu:

Foo(42, new Func<int, int>(Identity)); // prints "int" 

Vì vậy, ai đó có thể giải thích những gì đang xảy ra ở đây? Ngoài ra, tại sao nó làm việc với một lambda nhưng không phải với một nhóm phương pháp?

+4

Kiên nhẫn chờ Eric Lippert đăng * câu trả lời *. –

+0

Điều gì xảy ra trong C# 3? Tôi nghi ngờ điều này có thể có một cái gì đó để làm với phương sai loại trong generics. –

+0

@Anon, tôi đã không thử với C# 3, nhưng tôi không nghĩ rằng nó có bất cứ điều gì để làm với phương sai, bởi vì phương sai không áp dụng cho các loại giá trị –

Trả lời

3

Không phải đơn giản là vì loại trả về không phải là một phần của chữ ký của phương thức?

Thực tế là loại đối số của phương thức và kiểu trả về của Identity<T> được đảm bảo giống nhau không được tính toán bởi trình biên dịch khi cố gắng quyết định mức quá tải là Foo<TSource> là bắt buộc. Nếu loại trả lại không được xem xét thì Identity<int> có thể được chuyển đổi thành Func<int, int>, Func<int, double> hoặc Func<int, anything>.

+0

Tôi nghĩ rằng đây là nó. Hãy xem những gì Eric sẽ nói về điều này! – Lucero

+0

Điểm tốt, tôi quên rằng loại trả lại không phải là một phần của chữ ký ... –

1

Tôi nghĩ rằng LukeH là chính xác. Tuy nhiên, để trả lời câu hỏi thứ hai của bạn: đại biểu của lambda sẽ có tất cả các loại được điền (ví dụ: luôn là Func<int, int> nếu TSourceint), đó là lý do tại sao không có sự mơ hồ trong trường hợp đó. Nó không giống như một chữ ký hàm mà kiểu trả về bị bỏ qua.

+0

Vâng, tôi nghĩ đó là giải thích đúng ... –

+1

Tuyệt đối không. Lambdas rất nhạy cảm về ngữ cảnh. Trong thực tế, phiên bản lambda LÀ mơ hồ. http://ideone.com/IpUmb –

+0

@Ben Voigt, tôi không hiểu ý của bạn ... mã này được cho là minh họa điều gì? Nó hoạt động tốt với một lambda, do đó, nó phải được rõ ràng ... –

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