2012-08-24 31 views
6

F # 3.0 thêm kiểm tra chặt chẽ hơn cho các cuộc gọi đến baseprotected thành viên. Tôi có một cái gì đó giống như các lớp trừu tượng sau đây trong C# có protected static phương pháp trợ giúp được sử dụng bởi các lớp học có nguồn gốc.Hiểu thay đổi đối với việc sử dụng thành viên được bảo vệ/cơ sở trong F # 3.0

public abstract class Processor { 
    public abstract void Process(); 
    protected static void Helper(object arg) { } 
} 

Trong F #, một trong những phương pháp helper được thông qua như là một chức năng hạng nhất:

type DerivedProcessor() = 
    inherit Processor() 

    let init f = 
    f() 

    override x.Process() = 
    init Processor.Helper 

Nó biên dịch mà không khiếu nại trong 2.0, nhưng trong 3,0 tạo ra một lỗi:

A protected member is called or 'base' is being used. This is only allowed in the direct implementation of members since they could escape their object scope.

OK, thật dễ dàng để tuân thủ, chỉ cần thực hiện cuộc gọi trong một thành viên khác tĩnh

static member private HelperWrapper(arg) = Processor.Helper(arg) 

và chuyển thông tin đó. Nhưng tại sao?

C# không có vấn đề với cùng mẫu này.

public class HappyToCompile : Processor { 
    private void Init(Action<object> f) { 
     f(null); 
    } 

    public override void Process() { 
     Init(Helper); 
    } 
} 

Những câu hỏi:

  1. Tại sao kiểm tra chặt chẽ hơn thêm?
  2. (và có liên quan) Vấn đề khủng khiếp nào làm một địa chỉ giải quyết tầm thường như vậy?
  3. Có thiết kế nào tốt hơn để khuyến khích không?

Trả lời

5

Sử dụng kỹ năng thiết kế ngôn ngữ tâm linh của tôi, tôi đoán rằng F # 2.0 đang tạo mã không thể xác minh. Xem this đăng trên blog của Eric Lippert để được giải thích về một vấn đề liên quan trong C# (đã được khắc phục kể từ C# 4, IIRC).

Tóm lại, khi bạn tạo hàm F #, bạn đang tạo một lớp mới bắt nguồn từ FSharpFunc<_,_> và gọi phương thức được bảo vệ của bạn từ bên trong lớp đó không hợp lệ vì nó không nằm trong chuỗi thừa kế. Tất nhiên, thay vì không cho phép các cuộc gọi này, trình biên dịch chỉ có thể làm những gì bạn đang làm (tạo ra một phương pháp riêng và sử dụng nó), nhưng có lẽ những lợi ích này không được lớn hơn chi phí thực hiện cải tiến đó.

+0

Bạn đã trả lời câu hỏi đầu tiên và blog của Eric trả lời câu hỏi thứ hai. Thật dễ dàng để đánh bóng sự khác biệt giữa 'Func <_>' và 'FSharpFunc <_>'. Làm thế nào điều này có thể được refactored để loại bỏ 'bảo vệ'? – Daniel

+1

Vâng, tại sao nó được bảo vệ ngay từ đầu? Nếu bạn muốn nó chỉ có thể truy cập được vào các lớp con thì không có nhiều thứ bạn có thể làm. Có lẽ bạn có thể phơi bày 'Helper' như một thuộc tính được bảo vệ của kiểu' Action 'chứ không phải là một phương thức, nếu bạn mong đợi nó được truyền đi như một đại biểu. – kvb

+3

Đây sẽ là một bổ sung tốt cho [_Breaking Changes_] (http://msdn.microsoft.com/en-us/library/hh416791). Một [câu hỏi gần đây] (http://stackoverflow.com/q/11978234/162396) cũng có thể là một ứng cử viên tốt. – Daniel