6

baseF#3.0では、メンバーへの呼び出しとメンバーに対するより厳密なチェックが追加されていますprotectedprotected static派生クラスで使用されるヘルパーメソッドを持つC#の次の抽象クラスのようなものがあります。

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

F#では、これらのヘルパーメソッドの1つがファーストクラス関数として渡されます。

type DerivedProcessor() =
  inherit Processor()

  let init f =
    f ()

  override x.Process() =
    init Processor.Helper

2.0では文句なしにコンパイルされますが、3.0ではエラーが発生します。

保護されたメンバーが呼び出されるか、「base」が使用されています。これは、メンバーがオブジェクトスコープから脱出する可能性があるため、メンバーの直接実装でのみ許可されます。

OK、準拠するのは簡単です。呼び出しを別の静的メンバーでラップするだけです。

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. これが奨励することになっているより良いデザインはありますか?
4

1 に答える 1

5

私の精神的な言語設計スキルを使用して、F# 2.0 が検証不可能なコードを生成していると推測します。C# の関連する問題 (C# 4、IIRC 以降で修正済み) の説明については、Eric Lippert のブログのこの投稿を参照してください。

要するに、F# 関数を作成すると、実際には から派生した新しいクラスが作成FSharpFunc<_,_>されます。そのクラス内から保護されたメソッドを呼び出すことは、継承チェーンにないため有効ではありません。

もちろん、これらの呼び出しを禁止するのではなく、コンパイラはユーザーが行っていることを行う (プライベート メソッドを作成し、それを使用する) こともできますが、その利点は、その改善を実装するコストを上回らないと考えられていました。

于 2012-08-24T16:06:02.737 に答える