Lời nói đầu: Chuyển đến bản chỉnh sửa nếu bạn muốn giải thích đầy đủ. Spoiler: Phương thức mở rộng là một thủ thuật biên dịch, và thực sự có một đối số nhiều hơn chúng giống như khi bạn gọi chúng.
Đang ở độ phân giải của nhóm phương pháp. Rõ ràng trình biên dịch C# không dành thời gian để tìm ra liệu phương pháp bạn đang sử dụng có quá tải hay không; nó luôn luôn đòi hỏi một diễn viên rõ ràng. Kiểm tra:
What is a method group in C#?
Method Inference does not work with method group
Nhóm phương pháp mà trở lại từ reader.GetDoubleOrNull
được thu hẹp bởi những gì bạn cố gắng bỏ nó vào: GetDoubleOrNull
có thể tham khảo bất kỳ số lượng các phương pháp quá tải với tên đó. Bạn phải đúc nó một cách rõ ràng.
Điều thú vị là, bạn thậm chí không thể gán một nhóm phương pháp để một biến ngầm, đánh máy với cùng lý do:
var x = reader.GetDoubleOrNull;
thất bại trong việc biên dịch bởi vì nó đòi hỏi một diễn viên rõ ràng.
Sửa Tôi khá chắc chắn rằng sự nhầm lẫn ở đây đã làm với phương pháp khuyến nông:
Kiểm tra các lớp thử nghiệm sau đây:
public static class Extensions
{
public static List<T> GetList<T>(this IDataReader reader, Func<string, T> del)
{
throw new NotImplementedException();
}
public static double? GetDoubleOrNull(this IDataReader reader, string columnName)
{
throw new NotImplementedException();
}
public static double? blah(this string s)
{
throw new NotImplementedException();
}
}
Bạn có thể gọi thành công
var x = reader.GetList(Extensions.blah);
Tại sao điều này có thể là? blah
là một phương pháp mở rộng tĩnh, vì vậy, dựa trên bằng chứng của bạn, có vẻ như dòng trên không nên biên dịch. làm phức tạp thêm điều gì đó, hãy thêm phương pháp này:
public static List<T> GetList2<T>(this IDataReader reader, Func<IDataReader, string, T> del)
{
throw new NotImplementedException();
}
Bây giờ bạn có thể gọi
x = reader.GetList2(Extensions.GetDoubleOrNull);
và nó sẽ biên dịch đúng cách. Đưa cái gì?
Đây là câu trả lời: Phương pháp mở rộng không thực sự thêm phương thức vào đối tượng của bạn. Chúng thực sự là một thủ thuật biên dịch để cho phép bạn lập trình như thể những phương thức đó là một phần của các lớp học của bạn. Từ here:
Trong mã của bạn, bạn gọi phương thức mở rộng với cú pháp phương pháp . Tuy nhiên, ngôn ngữ trung gian (IL) được tạo bởi trình biên dịch dịch mã của bạn thành một cuộc gọi trên phương thức tĩnh. Do đó, nguyên tắc đóng gói không thực sự là vi phạm. Trên thực tế, các phương pháp mở rộng không thể truy cập các biến riêng lẻ trong loại chúng đang mở rộng.
Vì vậy, khi bạn gọi
var x = reader.GetDoubleOrNull("myColumnName");
những gì đang thực sự được biên soạn và thực hiện về cơ bản là thế này (một cuộc gọi hoàn toàn hợp pháp, mặc dù nó là một phương pháp mở rộng):
var x = Extensions.GetDoubleOrNull(reader, "myColumnName");
Vì vậy, , khi bạn cố gắng sử dụng GetDoubleOrNull
làm arg cho số Func<string, double?>
, trình biên dịch sẽ "Tôi có thể biến GetDoubleOrNull
thành Func<IDataReader, string, double?>
vì nó có hai đối số, nhưng tôi không k giờ làm thế nào để biến nó thành một Func<string, double?>
"
Mặc dù bạn đang gọi điện thoại nó như thể nó là một phương pháp thể hiện của các IDataReader
với một arg, nó không phải là: nó chỉ là một phương pháp tĩnh với hai args rằng C# trình biên dịch đã lừa bạn suy nghĩ là một phần của IDataReader
.
Rất thú vị. Một trình diễn rõ ràng '' var x = reader.GetList ((Func) Reader.GetDoubleOrNull) '' cũng hoạt động. Resharper đánh dấu diễn viên là thừa, nhưng không có trình biên dịch không thành công. Jon Skeet có ở đây không? –
Có cách nào để gọi Jon Skeet (hoặc có thể là Eric Lippert) không? Nói tên của họ ba lần hoặc một cái gì đó? – Chris
liên quan: http://stackoverflow.com/questions/7745852/method-inference-does-not-work-with-method-group và http://stackoverflow.com/questions/2057146/compiler-ambiguous-invocation-error -anonymous-method-and-method-group-with-fun – AakashM