Unable to load assemby built with F# compiler services via reflection

245 views Asked by At

I keep getting the following error message when I tried to load (via reflection) a .dll built using F# compiler services (even though the Equals method being complained about does exist in the build):

Unhandled Exception: System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types.
Method 'Equals' in type 'XXX' from assembly 'YYY', Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
   at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
   at System.Reflection.RuntimeModule.GetTypes()
   at System.Reflection.Assembly.GetTypes()

I'm using .NET Core on Ubuntu.

However, if I build using Visual Studio Code, I'm able to load the assembly. I opened both builds and I noticed the version that doesn't work has an override for one of the Equals method while the version that does, doesn't. I'm not sure if this is of consequence:

    [CompilerGenerated]
    public sealed bool Equals(object obj, IEqualityComparer comp)

vs

    [CompilerGenerated]
    public sealed override bool Equals(object obj, IEqualityComparer comp)

Additionally, when I check the references using dnSpy, the version that works has a reference to .netstandard while the version that does not does not have this reference. I've tried adding a reference to the .netstandard .dll as part of the compilation but this doesn't seem to have any effect.

The code I'm trying to build is a simple record, roughly equivalent to the following:

namespace Xxx

open System

type Yyy =
    {
        ServiceCategory : string
        DateRange : DateTime
    }

Here's the code I used to build using F# Compiler Services:

 // Detect the file location for the library that defines the object type
      let corelibRefLocation = typeof<Object>.GetTypeInfo().Assembly.Location
      let corelibRefDirectory = Path.GetDirectoryName(corelibRefLocation)
      let mscorlibRefLocation = sprintf @"%s/mscorlib.dll" corelibRefDirectory
      let systemRuntimeRefLocation = sprintf @"%s/System.Runtime.dll" corelibRefDirectory
      let netStandardRefLocation = sprintf @"%s/netstandard.dll" corelibRefDirectory

      let staticArgs =
            [|
             "fsc.exe"
             "--noframework"            
             "-o"; outputPath;
             "-a"; sourcePath           
            |]

      let references =
           [|
             "-r"; corelibRefLocation
             "-r"; systemRuntimeRefLocation
             "-r"; mscorlibRefLocation 
             "-r"; netStandardRefLocation 
           |]

      let args = Array.concat([|staticArgs; references|])         

      let errors, exitCode = 
          checker.Compile(args)
           |> Async.RunSynchronously 

      match (errors, exitCode) with
      | [||], 0 -> Console.WriteLine("OK!")
      | _ -> Console.WriteLine("Not OK!")

I'm not sure why the .dll isn't loading and what I need to do differently.

UPDATE: I've upgraded from .net Core 2.1. to .NET Core 3.0 and even though the generated code now no longer includes the override, the issue persists. The only significant difference between the version that works (compiled with VSCode) and the version that doesn't (compiled with FCS) that I can observe now is that the FCS version has an explicit reference to mscorlib and System.Private.CoreLib. However, I'm unable to get the code to compile without these explicit references.

0

There are 0 answers