Trước hết, tôi xin nói rằng câu trả lời của Jon là đúng. Đây là một trong những phần xù xì nhất của thông số kỹ thuật, rất tốt cho Jon vì đã đi sâu vào đầu tiên.
Thứ hai, hãy để tôi nói rằng dòng này:
Một chuyển đổi ngầm tồn tại từ một nhóm phương thức sang một loại đại biểu tương thích
(nhấn mạnh thêm) là sai lầm sâu sắc và đáng tiếc. Tôi sẽ nói chuyện với Mads về việc xóa từ "tương thích" ở đây.
Lý do điều này gây hiểu lầm và đáng tiếc là vì có vẻ như điều này đang gọi đến phần 15.2, "Khả năng tương thích của đại diện". Phần 15.2 đã mô tả mối quan hệ tương thích giữa các phương thức và kiểu đại biểu , nhưng đây là một câu hỏi về khả năng chuyển đổi của các nhóm phương thức và kiểu đại biểu , điều này là khác nhau.
Bây giờ chúng ta đã hiểu rõ điều đó, chúng ta có thể xem qua phần 6.6 của thông số kỹ thuật và xem những gì chúng ta nhận được.
Để thực hiện giải quyết quá tải, trước tiên chúng ta cần xác định xem quá tải nào là ứng viên có thể áp dụng . Một ứng cử viên có thể áp dụng nếu tất cả các đối số có thể chuyển đổi hoàn toàn thành các kiểu tham số chính thức. Hãy xem xét phiên bản đơn giản này của chương trình của bạn:
class Program
{
delegate void D1();
delegate string D2();
static string X() { return null; }
static void Y(D1 d1) {}
static void Y(D2 d2) {}
static void Main()
{
Y(X);
}
}
Vì vậy, chúng ta hãy đi qua nó từng dòng một.
Một chuyển đổi ngầm tồn tại từ một nhóm phương thức sang một loại đại biểu tương thích.
Tôi đã thảo luận về cách không may từ "tương thích" ở đây. Tiếp tục. Chúng tôi đang tự hỏi khi thực hiện giải quyết quá tải trên Y (X), nhóm phương thức X có chuyển đổi thành D1 không? Nó có chuyển đổi thành D2 không?
Cho một kiểu đại biểu D và một biểu thức E được phân loại là một nhóm phương thức, một phép chuyển đổi ngầm định tồn tại từ E sang D nếu E chứa ít nhất một phương thức có thể áp dụng [...] cho danh sách đối số được xây dựng bằng cách sử dụng tham số các loại và bổ ngữ của D, như được mô tả trong phần sau.
Càng xa càng tốt. X có thể chứa một phương thức có thể áp dụng với danh sách đối số của D1 hoặc D2.
Ứng dụng thời gian biên dịch của việc chuyển đổi từ nhóm phương thức E sang kiểu đại biểu D được mô tả như sau.
Dòng này thực sự không nói lên điều gì thú vị.
Lưu ý rằng sự tồn tại của chuyển đổi ngầm định từ E sang D không đảm bảo rằng ứng dụng thời gian biên dịch của chuyển đổi sẽ thành công mà không có lỗi.
Dòng này thật hấp dẫn. Nó có nghĩa là có những chuyển đổi ngầm tồn tại, nhưng có thể bị biến thành lỗi! Đây là một quy tắc kỳ lạ của C #. Để lạc đề một chút, đây là một ví dụ:
void Q(Expression<Func<string>> f){}
string M(int x) { ... }
...
int y = 123;
Q(()=>M(y++));
Hoạt động tăng dần là bất hợp pháp trong cây biểu thức. Tuy nhiên, lambda vẫn có thể chuyển đổi sang kiểu cây biểu thức, ngay cả khi việc chuyển đổi đã từng được sử dụng, đó là một lỗi! Nguyên tắc ở đây là chúng ta có thể muốn thay đổi các quy tắc của những gì có thể đi trong cây biểu thức sau này; thay đổi các quy tắc đó không nên thay đổi các quy tắc hệ thống kiểu . Chúng tôi muốn buộc bạn phải làm cho các chương trình của bạn trở nên rõ ràng ngay bây giờ , để khi chúng tôi thay đổi các quy tắc cho cây biểu thức trong tương lai để làm cho chúng tốt hơn, chúng tôi sẽ không đưa ra các thay đổi vi phạm trong độ phân giải quá tải .
Dù sao, đây là một ví dụ khác về loại quy tắc kỳ lạ này. Một chuyển đổi có thể tồn tại cho mục đích giải quyết quá tải, nhưng thực sự là một lỗi khi sử dụng. Mặc dù trên thực tế, đó không chính xác là tình huống mà chúng ta đang ở đây.
Tiếp tục:
Một phương thức duy nhất M được chọn tương ứng với một lệnh gọi phương thức có dạng E (A) [...] Danh sách đối số A là danh sách các biểu thức, mỗi biểu thức được phân loại là một biến [...] của tham số tương ứng trong biểu thức -parameter-list of D.
ĐỒNG Ý. Vì vậy, chúng tôi giải quyết quá tải trên X đối với D1. Danh sách tham số chính thức của D1 trống, vì vậy chúng tôi giải quyết quá tải trên X () và joy, chúng tôi tìm thấy một phương thức "string X ()" hoạt động. Tương tự, danh sách tham số chính thức của D2 trống. Một lần nữa, chúng tôi thấy rằng "string X ()" cũng là một phương thức hoạt động ở đây.
Nguyên tắc ở đây là việc xác định khả năng chuyển đổi của nhóm phương pháp đòi hỏi phải chọn một phương thức từ một nhóm phương pháp sử dụng độ phân giải quá tải và giải quyết quá tải không xem xét các kiểu trả về .
Nếu thuật toán [...] tạo ra lỗi, thì lỗi thời gian biên dịch sẽ xảy ra. Nếu không, thuật toán tạo ra một phương pháp tốt nhất M có cùng số lượng tham số với D và chuyển đổi được coi là tồn tại.
Chỉ có một phương pháp trong nhóm phương pháp X nên nó phải là phương pháp tốt nhất. Chúng tôi đã chứng minh thành công rằng chuyển đổi tồn tại từ X sang D1 và từ X sang D2.
Bây giờ, dòng này có liên quan không?
Phương pháp M đã chọn phải tương thích với kiểu đại biểu D, nếu không, xảy ra lỗi thời gian biên dịch.
Thực ra, không, không có trong chương trình này. Chúng tôi không bao giờ đi xa được khi kích hoạt dòng này. Bởi vì, hãy nhớ rằng, những gì chúng ta đang làm ở đây là cố gắng giải quyết quá tải trên Y (X). Chúng ta có hai ứng cử viên Y (D1) và Y (D2). Cả hai đều có thể áp dụng. Cái nào tốt hơn ? Không nơi nào trong đặc điểm kỹ thuật mà chúng tôi mô tả sự tốt hơn giữa hai chuyển đổi có thể có này .
Bây giờ, người ta chắc chắn có thể tranh luận rằng một chuyển đổi hợp lệ tốt hơn một chuyển đổi tạo ra lỗi. Điều đó thực sự có thể nói rằng, trong trường hợp này, việc giải quyết quá tải KHÔNG xem xét các kiểu trả về, đó là điều chúng ta muốn tránh. Sau đó, câu hỏi đặt ra là nguyên tắc nào tốt hơn: (1) duy trì bất biến mà giải pháp quá tải không xem xét các kiểu trả về, hoặc (2) cố gắng chọn một chuyển đổi mà chúng ta biết sẽ hoạt động trên một chuyển đổi mà chúng ta biết là không?
Đây là một cuộc gọi phán xét. Với lambdas , chúng tôi làm xem xét các kiểu trả về trong những loại chuyển đổi, trong phần 7.4.3.3:
E là một hàm ẩn danh, T1 và T2 là kiểu đại biểu hoặc kiểu cây biểu thức có danh sách tham số giống hệt nhau, kiểu trả về suy ra X tồn tại cho E trong ngữ cảnh của danh sách tham số đó và một trong các giá trị sau là:
Thật không may là chuyển đổi nhóm phương pháp và chuyển đổi lambda không nhất quán về mặt này. Tuy nhiên, tôi có thể sống với nó.
Dù sao, chúng tôi không có quy tắc "tốt hơn" để xác định chuyển đổi nào tốt hơn, X thành D1 hoặc X thành D2. Do đó, chúng tôi đưa ra một lỗi không rõ ràng về độ phân giải của Y (X).