How to generate C#-friendly, .Net 4.0 compatible types using F# 3.0 type providers
-
15-06-2021 - |
Question
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:
- MyGeneratedTypes.dll is generated in VS 2012 with the F# type provider mechanism.
- 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.
- A C# client in VS 2010 on a ".Net 4.5-free" system references MyGeneratedTypes.dll.
- When the C# client is compiled, MSBuild discovers the indirect reference to FSharp.Core 4.3 inside MyGeneratedTypes.dll.
- 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.)
- 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
".
Solution
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.