【问题标题】:Understanding a change to protected/base member usage in F# 3.0了解 F# 3.0 中受保护/基本成员使用的更改
【发布时间】:2012-08-24 15:29:29
【问题描述】:

F# 3.0 对baseprotected 成员的调用添加了更严格的检查。我在 C# 中有类似以下抽象类的东西,它有 protected static 派生类使用的辅助方法。

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

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

type DerivedProcessor() =
  inherit Processor()

  let init f =
    f ()

  override x.Process() =
    init Processor.Helper

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

调用了受保护的成员或正在使用“base”。这仅在成员的直接实现中允许,因为它们可以逃脱其对象范围。

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

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

并通过它。但为什么呢?

C# 使用相同的模式没有问题。

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

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

问题:

  1. 为什么要添加更严格的检查?
  2. (及相关)这种微不足道的解决方法解决了什么可怕的问题?
  3. 是否有更好的设计值得鼓励?

【问题讨论】:

    标签: inheritance f# compiler-errors protected f#-3.0


    【解决方案1】:

    使用我的通灵语言设计技能,我猜 F# 2.0 正在生成无法验证的代码。请参阅 Eric Lippert 博客上的 this 帖子,了解 C# 中的相关问题(自 C# 4, IIRC 以来已修复)。

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

    当然,除了不允许这些调用之外,编译器也可以只做你正在做的事情(创建一个私有方法并使用它),但也许人们认为好处不会超过实现该改进的成本。

    【讨论】:

    • 您回答了第一个问题,Eric 的博客回答了第二个问题。很容易掩盖Func&lt;_&gt;FSharpFunc&lt;_&gt; 之间的差异。如何重构以消除protected
    • 那么,为什么它首先受到保护?如果您希望它只能被子类访问,那么您可以做的事情并不多。也许您可以将 Helper 公开为 Action&lt;object&gt; 类型的受保护属性,而不是作为方法,如果您希望它作为委托传递。
    • 这将是对Breaking Changes 的一个很好的补充。另一个recent question 也可能是一个不错的候选人。
    • “为什么它首先受到保护?”我不说你不知道! :) 当然,因为它应该只对子类型可用。您的代表建议很好,如果它不破坏现有代码,我会使用它。看起来我被本地静态成员卡住了。
    • 我注意到 Tomas answered 不久前与您提出了一个相关问题,并且涉及了一些相同的问题。
    猜你喜欢
    • 2013-07-05
    • 2016-10-01
    • 2017-02-22
    • 1970-01-01
    • 2019-12-05
    • 1970-01-01
    • 1970-01-01
    • 2014-12-07
    相关资源
    最近更新 更多