RMills330
RMills330

Reputation: 329

Failure to discover property with reflection

Taking the following minimal example:

type IMyInterface =
    interface
        abstract member Name: string with get
    end

let testInstance =
    { new IMyInterface with
        member _.Name = "Hello Word" }

I would have naively expected a call to testInstance.GetType().GetProperties() to contain a PropertyInfo element corresponding to Name.

However, only an empty array is returned.

Using testInstance.GetType().GetProperty("Name") yields no better as it simply returns a <null> object.

More confusing still, Visual Studio 2022 IntelliSense lists Name as a valid property (as I'd expect).

How can I get a PropertyInfo corresponding to the Name property?

Upvotes: 1

Views: 91

Answers (1)

Fyodor Soikin
Fyodor Soikin

Reputation: 80744

In F# all interface implementations are private. This means that interface methods and properties do not appear as methods and properties of the implementing class.

In C# this works a bit differently: if you define a public member that happens to match an interface member, you don't have to explicitly tell the compiler that it's meant to be the interface implementation, the compiler will map it to the interface automatically for you.

So, for example, if you write this:

class MyClass : IMyInterface {
  public string Name { get; }
}

The C# compiler will actually compile it as this:

class MyClass : IMyInterface {
  public string Name { get; }
  string IMyInterface.Name { get { return this.Name; } }
}

(well, it's not exactly like that, but you get the idea)

But the F# compiler doesn't do that. If you want a class property in addition to the interface property, you have to roll one yourself:

type MyClass() =
  member __.Name = "Hello Word"
  interface IMyInterface with
    member this.Name = this.Name

But if you just want the interface property, you can get it off of the interface type:

let nameProp = typeof<IMyInterface>.GetProperty("Name")
let helloWorld = nameProp.GetValue testInstance

Or, if you don't know the interface type in advance, you can get it from the object type as well:

let intf = testInstance.GetType().GetInterfaces().[0]
let nameProp = intf.GetProperty("Name")
let helloWorld = nameProp.GetValue testInstance

Upvotes: 3

Related Questions