2011-11-23 12 views
21

Mã F # sau đây khai báo lớp cơ sở và hậu duệ. Lớp cơ sở có một phương thức ảo 'Test' với một cài đặt mặc định. Lớp con cháu ghi đè lên phương thức lớp cơ sở và cũng thêm một phương thức 'Thử nghiệm' đã được tải quá tải mới. Mã này biên dịch tốt và không có vấn đề gì khi truy cập một trong hai phương thức 'Thử nghiệm' con cháu.Không thể giải quyết phương thức F # đã bị ghi đè và quá tải từ C#

F # Code:

module OverrideTest 
    [<AbstractClass>] 
    type Base() = 
    abstract member Test : int -> int 
    default this.Test x = x + 1 

    type Descendant() = 
    inherit Base() 
    override this.Test x = x - 1 
    member this.Test (x, y) = x - y 

Tuy nhiên, cố gắng gọi override của hậu duệ của 'Test' từ C# kết quả trong một lỗi biên dịch:

var result = td.Test(3); <- No overload for method 'Test' takes 1 arguments

Các đầy đủ C# Code:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace Client 
{ 
    class Program 
    { 
    static void Main(string[] args) 
    { 
     var td = new OverrideTest.Descendant(); 
     var result = td.Test(3); 
     Console.WriteLine(result); 
     Console.ReadKey(); 
    } 
    } 
} 

Điều kỳ lạ là IntelliSense của VisualStudio thấy hai hàm bị quá tải và cung cấp s chữ ký chính xác cho cả hai. Nó không đưa ra cảnh báo hoặc lỗi trước khi xây dựng không thành công, và chỉ làm nổi bật dòng sau đó.

Tôi đã triển khai lại hoàn cảnh này hoàn toàn bằng C# và không gặp phải vấn đề tương tự.

Bất kỳ ai có ý tưởng gì đang diễn ra ở đây?

+0

Bạn đã so sánh IL đã phát ra ở cả hai ngôn ngữ chưa? – Oded

+0

Điều gì sẽ xảy ra nếu trong mã C# bạn upcast đến lớp cơ sở trước khi gọi phương thức? – Brian

+0

@Brian: Điều đó hoạt động. – Daniel

Trả lời

17

Không nghi ngờ gì bạn biết rằng nếu bạn bỏ qua thành viên Test(x,y) từ loại Descendant - hoặc chỉ cần đổi tên thành Test2(x,y) - thì mã C# sẽ biên dịch và chạy như mong đợi.

Nhìn vào IL tạo ra cho ban Descendant loại của bạn cung cấp một đầu mối:

.method public hidebysig virtual 
    instance int32 Test (
     int32 x 
    ) cil managed ... 

.method public 
    instance int32 Test (
     int32 x, 
     int32 y 
    ) cil managed ... 

Chú ý rằng không có hidebysig thuộc tính vào phương pháp Test(x,y).

ECMA CLI specification có nội dung sau để nói về hidebysig. (Mục 15.4.2.2, nhấn mạnh in đậm là của tôi.)

hidebysig is supplied for the use of tools and is ignored by the VES. It specifies that the declared method hides all methods of the base class types that have a matching method signature; when omitted, the method should hide all methods of the same name, regardless of the signature.

Vì vậy, F # biên dịch bỏ qua thuộc tính hidebysig, có nghĩa là phương pháp Test(x,y) giấu tất cả các phương pháp khác có tên Test. Mặc dù hidebysig chỉ là "để sử dụng các công cụ", có vẻ như trình biên dịch C# là một trong những công cụ sử dụng nó! Điều này trông giống như tôi có thể là một lỗi trong trình biên dịch F #, nhưng vì tôi chưa bao giờ nhìn vào thông số F # nên luôn luôn có thể cho phép hành vi này được cho phép/được chỉ định.

+0

+1: Đã phải đọc nó một vài lần để nắm bắt 'cùng tên'. IMO phần cuối cùng của câu nên được ** BOLD ** quá. – leppie

+0

Đó là _got_ là một lỗi. Đúng? – Daniel

+0

@Daniel: Tôi không thể nghĩ ra lý do tại sao 'hidebysig' nên được bỏ qua. (Tôi chưa từng biết điều này) – leppie