Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate C#-friendly, .Net 4.0 compatible types using F# 3.0 type providers

I want to generate "strong" types based on "weakly" typed data sources, using the F# 3.0 type provider mechanism. The generated types must be accessible from C# clients in an environment where only .Net 4.0 is installed, but not .Net 4.5. If .Net 4.0 compatibility is not possible, we cannot use type providers in our current large-scale ERP project.

So far, I have succeeded in creating MyGeneratedTypes.dll by following the tutorial on msdn (section "Providing Generated Types"), using the ProvidedTypeDefinition from "ProvidedTypes-0.2.fs", which is part of the F# 3.0 sample pack. (In order for it to work, I had to remove the line "File.Delete..." from the "ProvidedTypeDefinition.ConvertToGenerated..." method).

MyGeneratedTypes.dll has runtime version v4.0.30319, which is OK (the runtime of .Net 4.0). I can add a reference to MyGeneratedTypes.dll in a C#/.Net 4.0 application, and IntelliSense shows the types and members as expected. However, when I try to compile, the C# compiler fails and produces 'warning MSB3258: The primary reference "MyGeneratedTypes" could not be resolved because it has an indirect dependency on the .NET Framework assembly "FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" which has a higher version "4.3.0.0" than the version "4.0.0.0" in the current target framework.'

A look at IL Spy confirms that MyGeneratedTypes.dll indeed contains a reference to FSharp.Core 4.3, eventhough this reference is completely unnecessary. So far, I have found no way to prevent the F# compiler from putting this reference into the generated assembly. (Among other things, I have created a pure .Net 4.0 assembly in C# and passed it to the constructor of ProvidedTypeDefinition, but this has no influence).

Does anybody know a) how to get rid of the reference, or b) if this is only an F# 3.0 release candidate problem, which will be solved in the final release.

Edit

The conversation with @Brian has resulted in the following "partial" solution to the problem: You can compile a "pure C#/.Net 4.0" client referencing a library with F# 3.0 generated types, but only by calling the .Net 4.0 C# compiler (csc) directly from the command line. It does not work when compiling in VS 2010 or via MSBuild command line. I suspect this is caused by the following behavior:

  1. MyGeneratedTypes.dll is generated in VS 2012 with the F# type provider mechanism.
  2. During generation, a reference to FSharp.Core 4.3 is automatically inserted (even if not needed), without specifying "SpecificVersion:true" in the metadata for the dependency.
  3. A C# client in VS 2010 on a ".Net 4.5-free" system references MyGeneratedTypes.dll.
  4. When the C# client is compiled, MSBuild discovers the indirect reference to FSharp.Core 4.3 inside MyGeneratedTypes.dll.
  5. Because the indirect reference exists with "SpecificVersion:false", MSBuild emits the warning MSB3257 and refuses to pass the direct reference /r:"MyGeneratedTypes.dll" to the C# compiler (csc). (Note: MSBuild warnings cannot be suppressed in any way.)
  6. The C# compiler (csc) is called by MSBuild, without /r:"MyGeneratedTypes.dll". Therefore, it cannot compile, and emits compiler error CS0246: "The type or namespace name 'MyGeneratedTypes' could not be found (...)".

As far as I can tell, we're stuck with this problem unless the F# type provider mechanism is modified either a) to exclude the ref to FSharp.Core 4.3 when it is not needed in a generated assembly, or b) to include the ref with the metadata "SpecificVersion:true".

like image 606
Marc Sigrist Avatar asked Jun 20 '12 16:06

Marc Sigrist


1 Answers

Just add a reference to FSharp.Core 4.3.0.0 in the C# project (or ignore the warning). Despite the weird numbering convention, FSharp.Core 4.3.0.0 does not depend on anything in .Net 4.5, it only depends on .Net 4.0.

like image 95
Brian Avatar answered Jun 06 '23 19:06

Brian