Hello,
I'm trying to compile dynamic code that uses c# 7 tuples against .Net Framework 4.6.2. In this dynamic code I reference another dll (lib Bar in the example), also compiled against .Net 4.6.2, which references the ValueTuple nuget package (versions 4.3.1 and 4.4 were both tested). I run into problems when .Net Framework 4.7 is installed on my machine.
When trying to compile using CSharpCompilation (_Microsoft.CodeAnalysis.CSharp_ v 2.3.1), if I don't add ValueTuple as a reference, my other lib blocks the compilation:
Compilation error when processing Error (CS0570): 'IFoo.Bar(params ?)' is not supported by the language
And if I add the reference to ValueTuple (which is necessary when Framework 4.7 is not installed), I get the following errors:
Compilation error when processing Error (CS8137): Cannot define a class or member that utilizes tuples because the compiler required type 'System.Runtime.CompilerServices.TupleElementNamesAttribute' cannot be found. Are you missing a reference?
Error (CS8179): Predefined type 'System.ValueTuple`2' is not defined or imported
Error (CS0535): 'Foo' does not implement interface member 'IFoo.Bar(params (string a, string b)[])'
Error (CS8179): Predefined type 'System.ValueTuple`2' is not defined or imported
Error (CS8179): Predefined type 'System.ValueTuple`2' is not defined or imported
The code runs fine on a machine without Framework 4.7 when adding the reference to ValueTuple
Here is a minimal project to showcase the problem:
RoslynTest.zip
Is there a way to work around this (other than migrating my whole project to .net 4.7)?
@halgab Sorry you ran into this. That is a known type unification issue with the ValueTuple implementation in .NET Framework 4.7. It will be fixed in the next release of the .NET Framework.
Basically, when the compiler gets both references (mscorlib.dll and ValueTuple.dll) it will work if mscorlib.dll doesn't have ValueTuple. But with mscorlib.dll 4.7 the compiler will see two ValueTuple types and choke on the ambiguity.
You might also be able to make the reference to ValueTuple.dll optional, not including it when you detect that you are compiling on 4.7.
Aside from targeting .NET 4.7, there is a workaround, but it involves an internal API/flag (BinderFlags.IgnoreCorLibraryDuplicatedTypes). It is used by the scripting and debugger hosts (see https://github.com/dotnet/roslyn/pull/17192).
@halgab I didn't hear back from you. I'll go ahead and close the issue.
That is a known bug in 4.7 (which will be fixed in the following version of .NET Framework). There are two possible mitigations, listed above. Sorry for the inconvenience.
Sorry @jcouv, I waited to test your workaround over the weekend. Thank you very much for your feedback! I'll let you know if I manage to use your suggestions.
It worked! Thanks again! As reflexion is a bit over my league, I borrowed some code from OmniSharp/omnisharp-roslyn#785 to make the following helper:
internal static void SetIgnoreCorLibraryDuplicatedTypes(CSharpCompilationOptions compilationOptions)
{
var topLevelBinderFlagsProperty = typeof(CSharpCompilationOptions).GetProperty("TopLevelBinderFlags", BindingFlags.Instance | BindingFlags.NonPublic);
var binderFlagsType = typeof(CSharpCompilationOptions).GetTypeInfo().Assembly.GetType("Microsoft.CodeAnalysis.CSharp.BinderFlags");
var ignoreCorLibraryDuplicatedTypesMember = binderFlagsType?.GetField("IgnoreCorLibraryDuplicatedTypes", BindingFlags.Static | BindingFlags.Public);
var ignoreCorLibraryDuplicatedTypesValue = ignoreCorLibraryDuplicatedTypesMember?.GetValue(null);
if (ignoreCorLibraryDuplicatedTypesValue != null)
{
topLevelBinderFlagsProperty?.SetValue(compilationOptions, ignoreCorLibraryDuplicatedTypesValue);
}
}
I hope it will help anyone running into the same problem I had
Glad to hear. Thanks for sharing that snippet.