1

I have a class in C# which looks like this:

class A {
    protected SomeClass Field;
}

class B: A {}

and following code in F#:

type C() =
    inherit B()

    member this.SomeMethod() =
        let magic() = base.Field.SomeMoreMagic(someParam) //this.Field also fails
        ...

in which I want to access the protected field Field. I know that I could access protected fields from class B by simple type base.something (which is also answered here) but when I type base.Field to access protected field from class A I get an error that struct or class field is not accessible from this code location, because Field is declared in class A(?). My question is, is there some possibility to access it?

MNie
  • 1,347
  • 1
  • 15
  • 35
  • 2
    Possible duplicate of [F# Inherit from C# class + access protected fields](https://stackoverflow.com/questions/15091468/f-inherit-from-c-sharp-class-access-protected-fields). Looks like using the first part of the [accepted answer](https://stackoverflow.com/a/15092122/3872935) solves the problem. – Kote Jul 26 '17 at 07:45
  • @Kote nope, solution provided there is correct if I have field declared in B class instead of class A. – MNie Jul 26 '17 at 07:56
  • 2
    Actually, I can't reproduce your problem at all. If I use the exact code you show (but with a valid method body), I get `'base' values may only be used to make direct calls to the base implementations of overridden members`. If I write the code correctly, as `this.Field` instead of `base.Field`, it works fine. – Peter Duniho Jul 26 '17 at 08:16

2 Answers2

2

I found a resolution to my problem. Code like this is incorrect:

type C() =
    inherit B()

    member this.SomeMethod() =
        let d() = base.Field.SomeMagic(someParameter) //this.Field also fails
        d()

but code like this works correctly:

type C() =
    inherit B()

    member this.SomeMethod() =
        let stub = this.Field
        let d() = stub.SomeMagic(someParameter)
        d()
scrwtp
  • 13,437
  • 2
  • 26
  • 30
MNie
  • 1,347
  • 1
  • 15
  • 35
2

The reason why your stub workaround works is because you're trying to access the protected field within the body of a let-bound function d. Such functions are moved outside of the context they're defined in and compiled into subtypes of FSharpFunc type. That is, you get something like this in the compiled F# code (simplified picture):

internal class d@11 : FSharpFunc<Unit, int>
{
    public C @this;

    internal d@11(C @this)
    {
        this.@this = @this;
    }

    public override int Invoke(Unit unitVar0)
    {
        // this would be an attempt to access the protected field 
        // if the compiler allowed it.
        return @this.Field.SomeMoreMagic();  
    }
}

public class C : B
{
    public int SomeMethod()
    {
        FSharpFunc<Unit, int> d = new d@11(this);
        return d.Invoke(null);
    }
}

Which means that the block of code where you tried to access the protected field is no longer part of class C, and protected modifier prevents access there.

Whereas if you bind the value outside of d, you get something like this:

public class C : B
{
    public int SomeMethod()
    {
        SomeClass stub = this.Field;
        FSharpFunc<Unit, int> d = new d@11(stub);
        return d.Invoke(null);
    }
}

and no protected access happens outside class C anymore.

scrwtp
  • 13,437
  • 2
  • 26
  • 30