When compiling code using Roslyn as a library, it's fairly common to compile against framework runtime assemblies, since doing so is much easier than figuring out where reference assemblies are. For example:
``` c#
var compilation = CSharpCompilation.Create(assemblyName)
.AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));
If you need additional assemblies, you find some type from each assembly and use that. Specifically, using `dynamic` requires `Microsoft.CSharp` and `System.Dynamic.Runtime`, so you would add:
``` c#
.AddReferences(MetadataReference.CreateFromFile(typeof(Binder).Assembly.Location))
.AddReferences(MetadataReference.CreateFromFile(typeof(DynamicAttribute).Assembly.Location))
This works fine on .Net Framework, but not on .Net Core.
The first issue is that on .Net Core, some types are in separate assemblies. Specifically, using dynamic also requires System.Linq.Expressions:
``` c#
.AddReferences(MetadataReference.CreateFromFile(typeof(Expression).GetTypeInfo().Assembly.Location))
This is understandable. What is less understandable is that the assembly that contains `object` and other base types, `System.Private.CorLib` is not enough, you also need to explicitly reference two assemblies that mostly just forward types: `System.Runtime` and `mscorlib`:
``` c#
.AddReferences(MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("System.Runtime")).Location))
.AddReferences(MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("mscorlib")).Location))
This is necessary, because Microsoft.CSharp references System.Runtime, which forwards to mscorlib, which forwards to System.Private.CorLib.
Would it be possible for the Microsoft.CSharp runtime assembly (and similar assemblies) to directly reference the assembly that actually contains the types it uses, without any forwarding? It would simplify this kind of code.
For reference, here is a complete project showing what I'm talking about.
See also https://github.com/dotnet/roslyn/issues/12045, which inspired this request.
It's possible to simply collect all assemblies which netstandard assembly references:
```C#
private static List
{
// first, collect all assemblies
var assemblies = new HashSet
Collect(Assembly.Load(new AssemblyName("netstandard")));
//// add extra assemblies which are not part of netstandard.dll, for example:
//Collect(typeof(Uri).Assembly);
// second, build metadata references for these assemblies
var result = new List<MetadataReference>(assemblies.Count);
foreach (var assembly in assemblies)
{
result.Add(MetadataReference.CreateFromFile(assembly.Location));
}
return result;
// helper local function - add assembly and its referenced assemblies
void Collect(Assembly assembly)
{
if (!assemblies.Add(assembly))
{
// already added
return;
}
var referencedAssemblyNames = assembly.GetReferencedAssemblies();
foreach (var assemblyName in referencedAssemblyNames)
{
var loadedAssembly = Assembly.Load(assemblyName);
assemblies.Add(loadedAssembly);
}
}
}
```
Not sure if this is applicable for every case, but for me it resolved all the issues after migration to .NET Core 2.0 from .NET Framework 4.7 for Roslyn compiler.
Sorry it took a long time to respond, but unfortunately we have to keep the type forwards like they are for compatibility reasons with .NEt Standard, other versions of .NET Core, and .NET Framework. Also, it is not safe to depend on where types live in the runtime, as we can't guarantee that a type won't move into a different assembly across .NET Core versions, unless this is already at the bottom of the stack (meaning it is already in System.Private.CoreLib). One alternative you could do, is to try to reference everything inside the shared framework, so add some code that finds where System.Private.CoreLib.dll lives, and then just reference all dlls on that directory.
Closing this for now as we can't really fix this, but feel free to reopen if you have any follow up comments.
Most helpful comment
It's possible to simply collect all assemblies which CollectReferences()();
netstandardassembly references:```C#
private static List
{
// first, collect all assemblies
var assemblies = new HashSet
}
```
Not sure if this is applicable for every case, but for me it resolved all the issues after migration to .NET Core 2.0 from .NET Framework 4.7 for Roslyn compiler.