2012-03-07 33 views
13

Tôi có hai phương pháp khuyến nông trên IDataReader có chữ ký sau đây:Chuyển đổi một nhóm phương pháp mở rộng cho một đại biểu với một kiểu generic

internal static List<T> GetList<T>(this IDataReader reader, Func<string, T> del) 

internal static double? GetDoubleOrNull(this IDataReader reader, string columnName) 

GetDoubleOrNull không có bất kỳ quá tải.

Ở những nơi khác, tôi có thể làm

Func<string, double?> del = reader.GetDoubleOrNull; 

var x = reader.GetList(del); 

hoặc

var x = reader.GetList<double?>(reader.GetDoubleOrNull); 

hoặc chỉ vượt qua trong một phương pháp dụ như

public double? blah(string s) 

var x = reader.GetList(blah); 

nhưng tôi không thể làm

var x = reader.GetList(reader.GetDoubleOrNull); 

Trình biên dịch cung cấp cho các lỗi

cannot convert from 'method group' to 'System.Func<string,double?>' 

Tôi không hiểu điều này. Tôi nghĩ rằng vì không có quá tải trên GetDoubleOrNull, sẽ không có độ phân giải quá tải và có thể suy ra thông số loại từ chữ ký phương thức.

Phần khó hiểu nhất là cách nó hoạt động như thế nào khi đi qua số blah.

+3

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? –

+3

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

+1

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

Trả lời

0

GetDoubleOrNull trả về gấp đôi? GetList hy vọng một IDataReader và System.Func<string,int?>

Các thông báo lỗi là một chút sai lệch

đôi nào? blah (string s)

var x = reader.GetList (blah);

blah là đại biểu trong cuộc gọi này. Trong GetList (GetDoubleOrNull) đó là kết quả của việc có được doubleOrNull.

Câu hỏi hay. Làm đăng câu trả lời cho dù tôi đã giúp hay không.

+0

'' int'' phải là một lỗi đánh máy, thay đổi nó thành '' double'' vẫn cho lỗi trình biên dịch. –

+0

Jacek là chính xác. Lỗi của tôi. Lấy làm tiếc. – Moss

+1

Bạn nói "Trong GetList (GetDoubleOrNull) đó là kết quả của việc có được doubleOrNull" nhưng điều này không đúng. Trong trường hợp này 'GetDoubleOrNull' không được đánh giá, nó đang được coi là một nhóm phương thức. – Chris

8

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.

+0

Câu trả lời và nghiên cứu xuất sắc. Tôi muốn +1 lại. ;-) – Chris

+3

Tôi không phải là Jon Skeet, nhưng tôi làm những gì tôi có thể: D – eouw0o83hf

+0

Cảm ơn câu trả lời của bạn. Thật không may, tôi dường như không hiểu rõ vấn đề. Câu hỏi đầu tiên bạn tham chiếu là câu hỏi mà tôi biết. Tôi đọc phần thứ hai, cũng như những bài được đăng bởi AakashM, và có vẻ với tôi rằng nó đi xuống đến độ phân giải quá tải không tính đến các loại trả về. Tôi hiểu điều đó. Nhưng làm thế nào, sau đó, không đi qua trong công việc 'blah'? Không có độ phân giải quá tải xảy ra trong trường hợp đó? Nếu không, tai sao không? Nếu vậy, nó thành công như thế nào? – Moss

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