2013-06-14 25 views
8

Với lớp sau đây:cast Implicit của Func <MyType> để MyType

public class MyType 
{ 
    public static implicit operator MyType(Func<MyType> wrapper) { 
     return wrapper(); 
    } 
} 

Từ diễn viên tiềm ẩn của Func<MyType> để MyType, tôi giả định sau đây sẽ có thể:

public MyType MyTypeWrapper() { 
    return new MyType(); 
} 

public void MyTestMethod() { 
    MyType m = MyTypeWrapper; // not a call! 
} 

Tuy nhiên tôi nhận được:

Không thể chuyển đổi nhóm phương thức 'MyTypeWrapper' thành loại không được ủy quyền 'T est.MyType '. Bạn có định gọi phương thức này không?

nào, không may cho tôi, khi tìm kiếm (như tôi mong đợi nửa) dẫn đến tonsofquestions mà câu trả lời là:

Hey, ya dun goofed; quăng () vào cuối WhateverMethod!

Bây giờ, khi tôi đang gõ những dòng này, tôi đã nhận thấy rằng một rõ ràng diễn viên nào trong thực tế biên dịch:

MyType m = (MyType) MyTypeWrapper; 

Tại sao nó mà tôi không thể mặc nhiên bỏ Func<MyType> để MyType như Tôi đã mô tả?

Trả lời

11

Bạn đang sử dụng chuyển đổi ẩn được tích hợp sẵn từ nhóm phương pháp thành Func<MyType>.

Trình biên dịch sẽ không thực hiện hai chuyển đổi ngầm cùng một lúc.

Một khi bạn có một diễn viên rõ ràng cho lớp học của bạn, trình biên dịch biết để tìm một diễn viên tiềm ẩn cho bất kỳ loại có thể được đúc một cách rõ ràng để lớp học của bạn.

+0

Ah, tôi hiểu. Bất kỳ cách nào để giảm thiểu "tính năng" trình biên dịch này? (* Tôi đoán "Không" *) – Dan

+1

@Bracketworks: Không. Các nhóm phương pháp là một loại biểu thức rất khác thường ở chỗ chúng không có một loại và của chính chúng (như 'null' và lambdas). – SLaks

+1

@Bracketworks Nó không thực sự khả thi, ngay cả khi họ muốn, theo câu trả lời của tôi. Trình biên dịch đang tìm kiếm một chuyển đổi từ kiểu này sang loại khác và khi nó chuyển đổi cho một chuyển đổi thực hiện chính xác điều đó, không phải bất kỳ chuyển đổi nào chuyển sang bất kỳ loại nào có chuyển đổi thành loại bạn muốn. Điều đó được ra khỏi bàn tay * thực sự * nhanh chóng cho cả trình biên dịch, và cũng là lập trình viên. Hãy tưởng tượng tôi có một lớp học trung bình với một sự chuyển đổi từ đối tượng với tôi và từ tôi sang đối tượng. Bây giờ bất kỳ nhiệm vụ nào có thể liên quan đến cả hai hoạt động đang chạy, cho phép tôi làm đủ mọi thứ có ý nghĩa. – Servy

1

Vì trình biên dịch C# không thể chuyển đổi MyTypeWrapper thành một Func<MyType>(MyTypeWrapper). Có sự khác biệt giữa nhóm phương pháp và đại biểu thực tế.

này biên dịch và chạy tốt:

MyType m = new Func<MyType>(MyTypeWrapper); 

Có một chuyển đổi ngầm từ một nhóm phương pháp để một loại đại biểu phù hợp với nhóm, và có người dùng của bạn được xác định chuyển đổi ngầm từ ủy nhiệm cho một loại. Ý tưởng chung ở đây là trình biên dịch sẽ chỉ sử dụng một chuyển đổi ngầm trong một hàng tại một thời điểm. Khi nó có A và cần một C, nó sẽ tìm kiếm các chuyển đổi từ A đến C, không phải từ A đến bất kỳ loại B nào và từ loại đó đến C. Thuật toán đó chuyển từ O (n) sang O (n^2) (không thành đề cập đến có thể là khá khó hiểu cho các lập trình viên).

Lý do mã của bạn hoạt động khi sử dụng dàn diễn viên rõ ràng đến MyType là bạn không còn chuỗi chuyển đổi tiềm ẩn nữa.

+3

Điều đó không giải thích tại sao '(MyType) MyTypeWrapper' hoạt động – SLaks

1

Chữ ký của MyTestMethod ĐẢM BẢO chữ ký của Func<MyType> nhưng KHÔNG phải là Func<MyType>.Func đã xác định một số tiềm ẩn phôi tự để cho phép bạn gán các phương pháp như funcs, nhưng bạn phải đúc một cách rõ ràng cho chữ ký để áp dụng, bởi vì trình biên dịch sẽ không chuỗi ngầm phôi cùng dành cho bạn:

MyType m = (Func<MyType>)MyTypeWrapper; // not a call! 
12

Đây là bất hạnh . Tôi khá chắc chắn rằng bạn đã tìm thấy một lỗi trình biên dịch, và phần này của đặc điểm kỹ thuật là vô cùng khó khăn để đọc.

Mục 6.4.4 của đặc tả C# 4 giải thích lý do chuyển đổi ngầm của bạn là bất hợp pháp.

Thuật toán diễn ra như thế này. Đầu tiên hãy xem loại nguồn và loại mục tiêu. Không có loại nguồn nào vì nhóm phương pháp không có loại. Loại mục tiêu là MyType. Vì vậy, hãy tìm kiếm MyType để chuyển đổi ẩn do người dùng xác định. Bây giờ câu hỏi đặt ra là: tập hợp của các toán tử do người dùng xác định có thể áp dụng được ... chuyển đổi từ một kiểu bao gồm S là gì? S là loại nguồn và chúng tôi đã thiết lập rằng không có loại nguồn. Vì vậy, đây là bằng chứng cho thấy việc chuyển đổi sẽ thất bại. Nhưng ngay cả khi trình biên dịch vì lý do nào đó quyết định rằng chuyển đổi Func<MyType> của bạn có thể áp dụng, thì quy tắc là chuyển đổi ngầm ẩn tiêu chuẩn ... được thực hiện. Chuyển đổi nhóm phương pháp được cố tình không được phân loại là chuyển đổi chuẩn.

Vì vậy, đó là lý do tại sao nó phải là bất hợp pháp.

Tại sao diễn viên rõ ràng hợp pháp?

Không có lý do nào cho điều đó. Điều này dường như là một lỗi.

Điều này thật không may; nhiều lời xin lỗi vì lỗi. Tôi sẽ báo cáo cho các đồng nghiệp cũ của tôi; nếu họ có một phân tích xung đột với tôi, tôi sẽ cập nhật câu trả lời.

CẬP NHẬT: Các đồng nghiệp cũ của tôi thông báo cho tôi rằng vấn đề spec trong đó biểu thức nguồn được giả định là có loại sẽ được giải quyết bằng cách viết lại trong bản phát hành tiếp theo của thông số. Không có từ nào cho dù hành vi cast rõ ràng là một lỗi.

+0

Tôi hơi ngạc nhiên khi chuyển đổi rõ ràng đã hoạt động. Bạn không đồng ý với dòng cuối cùng của câu trả lời của tôi? (Tôi đã không tìm kiếm nó trong spec) – SLaks

+2

@SLaks: Trình biên dịch biết nhìn vào 'MyType' trong trường hợp ngầm bởi vì nó biết rằng đây là loại mục tiêu duy nhất có thể có của chuyển đổi ngầm định. Tương phản với kịch bản này: nếu bạn có chuyển đổi * rõ ràng do người dùng xác định từ Giraffe sang Fruit và bạn đưa tham chiếu đến Animal để nhập Banana thì trình biên dịch sẽ tìm kiếm Animal, Banana và Fruit cho các toán tử chuyển đổi nhưng không tìm kiếm Con hươu cao cổ, nếu chuyển đổi do người dùng xác định được khai báo trên Hươu cao cổ, bạn sẽ không may mắn. –

+0

Tôi rất vui vì đã thử dàn diễn viên rõ ràng rồi! Cảm ơn bạn đã cập nhật @EricLippert, mong muốn biết thêm thông tin :) – Dan

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