F # фактически компилирует частные члены как внутренние в IL. Ошибка?

Я всегда предполагал, что ключевые слова управления доступом в F # (public, private, internal) работают так же, как и на С#. В самом деле, из документации MSDN Контроль доступа (F #):

  • общедоступный указывает, что к объекту могут быть доступны все вызывающие абоненты.
  • внутренний указывает, что к объекту можно получить доступ только из той же сборки.
  • private указывает, что к объекту можно получить доступ только из закрывающего типа или модуля.

Это похоже на мое предположение, а также несколько ответов на тему, приведенную здесь в SO.

Однако, когда я вошел в скомпилированный код с Reflector, я обнаружил, что все те члены, объявленные как private, фактически скомпилированы как внутренние (видимость сборки), которые не соответствуют документации.

Чтобы избежать каких-либо сомнений, я создал небольшой тест, чтобы подтвердить это.

Код F #:

// Make internals visible to other assemblies
[<assembly:InternalsVisibleTo("MyCSharpAssembly")>]


// OK. Expect: "internal static class PrivateModule" in C#
module private PrivateModule =

    // FAIL. Expect: "private static void privateStaticMethod()" in C#
    let private privateStaticMethod() = ignore()

// OK. Expect: "internal class InternalClass" in C#
type private InternalClass() =

    // FAIL. Expect: "private int privateInstanceField" in C#
    let privateInstanceField = 0

    // FAIL. Expect: "private static int privateStaticField" in C#
    static let privateStaticField = 0

    // FAIL. Expect: "private int privateInstanceMethod()" in C#
    let privateInstanceMethod() = privateInstanceField

    // FAIL. Expect: "private in PrivateInstanceMember()" in C#
    member private this.PrivateInstanceMember() = privateInstanceField

    // OK. Expect: "internal int InternalInstanceMember" in C#
    member internal this.InternalInstanceMember() = privateStaticField

Я собрал немного кода на С#, чтобы убедиться, что я не воображаю ничего.

тестовый код С#, и все компилируется.

public class TestVisibility
{
    // This is a demo to verify that the members are indeed
    // internal (assembly) and can be accessed from C# if the
    // F# assembly is compiled with [<assembly:InternalsVisibleTo("C# assembly")>]
    public void Run()
    {
        // All of these compile.
        PrivateModule.privateStaticMethod();

        InternalClass x = new InternalClass();

        int a = InternalClass.privateStaticField;
        var b = x.InternalInstanceMember();
        var c = x.PrivateInstanceMember();
        var d = x.privateInstanceField;
        var f = x.privateInstanceMethod();
    }
}

Я использовал VS2012, ориентированный на .NET 4.0, все настройки по умолчанию. Пробовал режимы Debug и release с одинаковыми результатами.

Вопрос. Каково фактическое ожидаемое поведение по дизайну? Это ошибка? Или я делаю что-то неправильно?

Предложение. Если это предполагаемое поведение, возможно, было бы неплохо четко указать это в документации где-нибудь?

Ответы

Ответ 1

Из спецификации F # 3.0: скомпилированная форма CLI всех непубличных объектов внутренняя.