Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding a method from a C# class in F# language makes the method not be introspectable?

I have the following C# classes:

public class Foo {
    protected virtual void Bar (){
    }
}

public class Baz : Foo {
    protected override void Bar (){
    }
}

If I introspect them, the method Bar is always there:

[<EntryPoint>]
let main args =
    let methodFromFoo = typedefof<Foo>.GetMethod("Bar", BindingFlags.Instance ||| BindingFlags.NonPublic)
    if (methodFromFoo <> null) then
        Console.WriteLine ("methodFromFoo is not null")
    else
        Console.WriteLine ("methodFromFoo is null")

    let methodFromBaz = typedefof<Baz>.GetMethod("Bar", BindingFlags.Instance ||| BindingFlags.NonPublic)
    if (methodFromBaz <> null) then
        Console.WriteLine ("methodFromBaz is not null")
    else
        Console.WriteLine ("methodFromBaz is null")

The result of this is is not null for both cases.

However, when I do the same with an F# class the result is different:

type FSharpBaz() =
    inherit Foo()
    override this.Bar () =
        Console.WriteLine ("yeh")

[<EntryPoint>]
let main args =
    let methodFromFsharp = typedefof<FSharpBaz>.GetMethod("Bar", BindingFlags.Instance ||| BindingFlags.NonPublic)
    if (methodFromFsharp <> null) then
        Console.WriteLine ("methodFromFsharp is not null")
    else
        Console.WriteLine ("methodFromFsharp is null")

But why??? Cannot I get the method via reflection if my class is made with F#? I'm devastated.

like image 274
knocte Avatar asked Feb 14 '23 03:02

knocte


1 Answers

The reason why you don't see it is because FSharpBaz.Bar is emitted as public and not protected. You can verify this by looking at the code in ildasm. This is actually completely legal behavior and is covered in section 8.5.3.2 of the CLI spec

When a type defines a virtual method that overrides an inherited definition, the accessibility shall either be identical in the two definitions or the overriding definition shall permit more access than the original definition.

As to why F# uses public here, that is simply the default for member definitions

If no access specifier is used, the default is public, except for let bindings in a type, which are always private to the type (Link)

like image 131
JaredPar Avatar answered Mar 22 '23 22:03

JaredPar