Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type.GetType() not working for F# type in C# code

I have an F# assembly called Assembly1

I have the following module:

namespace Assembly1

module MyModule =
   type MyClass(x: int, y: int) =
   new() = MyClass(0, 0)

In a C# assembly that references this F# assembly, the following code gives me a value of 'null' back:

var myType = Type.GetType("Assembly1.MyModule.MyClass, Assembly1");

Is what I am trying to do not possible?

like image 853
bstack Avatar asked Oct 22 '15 08:10

bstack


2 Answers

To add to Mark's answer, it's also worth noting that a lot of modules in F# are represented by different names in IL (and therefore non-F# languages) than they appear with in F# itself.

For example, this piece of code:

open System
open System.Reflection
open Microsoft.FSharp.Reflection

let private core =
    AppDomain.CurrentDomain.GetAssemblies()
    |> Seq.find (fun a -> a.GetName().Name = "FSharp.Core")

let private seqMod =
    core.GetTypes()
    |> Seq.filter FSharpType.IsModule
    |> Seq.find (fun t -> 
                   t.FullName = "Microsoft.FSharp.Collections.SeqModule")

Will find the Seq module in FSharp.Core.

The FSharp.Reflection namespace has a bunch of helper methods to make working with F# specific types with System.Reflection a little bit less painful, so it's worth loading up a couple of assemblies in FSI and having a play with those if you're going to be doing a lot of reflection work with F# code.

You can create modules with "mismatching" names like this yourself using the CompiledName attribute - this is especially useful for those times where you want a type and a module with the same name. The normal convention (as shown with the Seq type/module) is to annotate the module with Compiled name.

[<CompiledName("MyTypeModule")>]
module MyType =
    let getString m =
        match m with
        | MyType s -> s
like image 193
mavnn Avatar answered Sep 16 '22 12:09

mavnn


Since you've put MyClass into a module, it's compiled as a nested class. Its name is Assembly1.MyModule+MyClass.

From C#, you should be able to load it like this:

var myType = Type.GetType("Assembly1.MyModule+MyClass, Assembly1");

If you don't want to have nested classes (which are generally frowned upon in C#), you can define it directly in a namespace:

namespace Assembly1.LibraryXyz

type MyClass(x: int, y: int) = class end

This class will have the name Assembly1.LibraryXyz.MyClass.

like image 36
Mark Seemann Avatar answered Sep 17 '22 12:09

Mark Seemann