Pavel Voronin
Pavel Voronin

Reputation: 13983

What is going with visibility of protected overridden method in F#?

I have different result for reflection depending on the language: C# vs F#

C#

public abstract class TestHandler : HttpMessageHandler
{
    public abstract Task<HttpResponseMessage> MockableSendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }
}

var methods = typeof(TestHandler).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance);

methods contains SendAsync, Dispose, MemberwiseClone, and Finalize.

Now F#

open System.Net.Http
open System.Threading
open System.Threading.Tasks
open System.Reflection

[<AbstractClass>]
type TestHandler() = 
    inherit HttpMessageHandler()
    abstract member MockableSendAsync: HttpRequestMessage * CancellationToken -> Task<HttpResponseMessage>
    override this.SendAsync(request, cancellationToken) = this.MockableSendAsync(request, cancellationToken)

let methods = typeof<TestHandler>.GetMethods(BindingFlags.NonPublic ||| BindingFlags.Instance)

methods contains only three methods, SendAsync is absent.

However, if I use Public binding flag, methods contains more entries including SendAsync:

let methods = typeof<TestHandler>.GetMethods(BindingFlags.NonPublic ||| BindingFlags.Instance ||| BindingFlags.Public)

However, there is a difference in RuntimeMethodInfo of C# and F# versions.

For C# Attributes property is:
- PrivateScope, Family, Virtual, HideBySig,

whereas for F# it is:
- PrivateScope, Public, Virtual, HideBySig

WTF?! Where is promised respect for protected visibility modifier?

Upvotes: 0

Views: 74

Answers (1)

Asti
Asti

Reputation: 12667

I'm sorry to say that they never did promise respect for the visibility modifier.

In the F# 4.1 Spec, section 10.5:

Accessibility Annotations

The table lists the accessibilities that can appear in user code:

public

No restrictions on access.

private

Access is permitted only from the enclosing type, module, or namespace declaration group.

internal

Access is permitted only from within the enclosing assembly, or from assemblies whose name is listed using the InternalsVisibleTo attribute in the current assembly.

...

The CLI compiled form of all non-public entities is internal.

Note: The family and protected specifications are not supported in this version of the F# language.

What reflection is showing you is unfortunately, expected behavior.

Upvotes: 3

Related Questions