了解F#3.0中对受保护/基本成员使用的更改

Dan*_*iel 6 inheritance f# compiler-errors protected f#-3.0

F#3.0为呼叫baseprotected成员添加了更严格的检查.我有类似C#中的以下抽象类,它有protected static派生类使用的辅助方法.

public abstract class Processor {
    public abstract void Process();
    protected static void Helper(object arg) { }
}
Run Code Online (Sandbox Code Playgroud)

在F#中,其中一个辅助方法作为第一类函数传递:

type DerivedProcessor() =
  inherit Processor()

  let init f =
    f ()

  override x.Process() =
    init Processor.Helper
Run Code Online (Sandbox Code Playgroud)

它在2.0中没有投诉编译,但在3.0中产生错误:

被调用的受保护成员或正在使用"基础".这只能在成员的直接实现中使用,因为它们可以逃避它们的对象范围.

好的,它很容易遵守,只需将调用包装在另一个静态成员中

static member private HelperWrapper(arg) = Processor.Helper(arg)
Run Code Online (Sandbox Code Playgroud)

并通过那个intead.但为什么?

C#对于同样的模式没有问题.

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

    public override void Process() {
        Init(Helper);
    }
}
Run Code Online (Sandbox Code Playgroud)

问题:

  1. 为什么要加入更严格的检查?
  2. (和相关的)这样一个琐碎的解决方案解决了什么可怕的问题?
  3. 是否有一个更好的设计,这应该鼓励?

kvb*_*kvb 5

使用我的心灵语言设计技巧,我猜F#2.0正在生成无法验证的代码.见对埃里克利珀的博客文章在C#中的一个相关问题的解释(因为C#4,IIRC已经固定).

简而言之,当您创建一个F#函数时,您实际上正在创建一个派生自的新类FSharpFunc<_,_>,并且从该类中调用受保护的方法是无效的,因为它不在继承链中.

当然,编译器可以只执行您正在执行的操作(创建一个私有方法并使用它),而不是禁止这些调用,但可能认为这些优点不会超过实现该改进的成本.

  • 这将是[_Breaking Changes_](http://msdn.microsoft.com/en-us/library/hh416791)的一个很好的补充.另一个[最近的问题](http://stackoverflow.com/q/11978234/162396)也可能是一个很好的候选人. (3认同)