roslyn: CSharpCompilation - error CS0012: The type 'Object' is defined in an assembly that is not referenced.

Migrating a solution from .NET Core 3.1 to .NET 5.0 fail on CSharpCompilation emit. I was able to reproduce the problem with a minimal project as described on the steps bellow.

Version Used: Microsoft.CodeAnalysis.CSharp (3.8.0)

Steps to Reproduce:

  1. Create a C# DotNetCore (Console Application)
  2. Change TFM to .NET 5.0
  3. Add the following class on ConsoleApp1
 class Program
    {
        static void Main(string[] args)
        {
            string testClass = "" +
                "using System;" +
                "public class TesteClass" +
                "{" +
                    "public TesteClass()" +
                    "{" +
                        "var obj = new Object();" +
                        "Console.WriteLine(obj);" +
                    "}" +
                "}";

            var references = new List<MetadataReference>
                {
                    MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
                    MetadataReference.CreateFromFile(typeof(Console).Assembly.Location),
                    MetadataReference.CreateFromFile(typeof(System.Runtime.AssemblyTargetedPatchBandAttribute).Assembly.Location),
                    MetadataReference.CreateFromFile(typeof(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo).Assembly.Location),
                };

            var compilation = CSharpCompilation.Create(Guid.NewGuid().ToString() + ".dll")
                .WithOptions(new CSharpCompilationOptions(Microsoft.CodeAnalysis.OutputKind.DynamicallyLinkedLibrary))
                .AddReferences(references)
                .AddSyntaxTrees(CSharpSyntaxTree.ParseText(testClass));

            var eResult = compilation.Emit("test.dll");

            Console.ReadLine();
        }
    }

Expected Behavior: Success: true, same result as dotnet core 3.1

Actual Behavior: error CS0012: The type ‘Object’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’. error_roslyn_dotnet5

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 16 (4 by maintainers)

Commits related to this issue

Most upvoted comments

@tkw-devs you can solve using this marked code:

image

The discussion in this thread finally prompted me to turn roslyn-codedom into something that was more productized.

https://github.com/jaredpar/basic-reference-assemblies

This repository now builds easy to use reference assembly DLLs. The README.md has a lot of details but in short using the NuPkg defined there you can create in memory compilations like so:

var code = @"
using System;
static class Program
{
    static void Main()
    {
        var tuple = (Part1: ""hello"", Part2: ""world"");
        Console.WriteLine($""{tuple.Part1} {tuple.Part2}"");
    }
}
";

var compilation = CSharpCompilation
    .Create(
        "HelloWorld.dll",
        new[] { CSharpSyntaxTree.ParseText(code) },
        references: ReferenceAssemblies.Net50);

using var fileStream = new FileStream(@"p:\temp\helloworld.exe", FileMode.Create, FileAccess.ReadWrite);
var emitResults = compilation.Emit(fileStream);

this is works the key is:

        Assembly.GetEntryAssembly().GetReferencedAssemblies()
            .ToList()
            .ForEach(a => references.Add(MetadataReference.CreateFromFile(Assembly.Load(a).Location)));

I have the same problem

This behavior is “By Design”. The problem here is that the technique you are using here to add references is using implementation assemblies, not reference assemblies. The stability of APIs in implementation assemblies is not guaranteed over time. The solution here is to reference the reference assemblies in the project.

Unfortunately it’s not as easy to reference them, they don’t have the handy typeof(object).Assembly.Location expression. It requires a bit of work to package them with your application to be usable. The following project has a base implementation of packaging these references that you can look at for an approach here.

https://github.com/jaredpar/roslyn-codedom

@Mun1z

The example I gave works perfectly in the .net core, when upgrading to .net 5 it stops working, having to be implemented the way it was done, I still think it should work as it did before, imagine there each dotnet version as previous things stop working and you have to rewrite again?

The problem here is that your sample referenced the implementation assemblies and that is officially not supported by the runtime team. The are free to refactor the implementation assemblies as they choose. In this case that resulted in a new assembly that you’re not referencing here that is necessary for a successful compilation in .NET 5. Using the reference assemblies though means you’ll get a consistent experience between .NET Core versions.

To be clear this is not something the compiler controls. The compiler is working with the inputs its given here and in this case there aren’t sufficient references for us to run a compilation.

@tkw-devs I downloaded the repository on link that @jaredpar sent: https://github.com/jaredpar/roslyn-codedom

Here, you have powershell script named: Generate.ps1 . I edited it to add .NET 5.0 At about line 100, calls of Add-TargetFramework looks like this:

Add-TargetFramework "NetCoreApp31" 'Microsoft.NETCore.App.Ref\3.1.0\ref\netcoreapp3.1' 
Add-TargetFramework "Net50" 'Microsoft.NETCore.App.Ref\5.0.0\ref\net5.0' 
Add-TargetFramework "NetStandard20" 'netstandard.library\2.0.0\build\netstandard2.0\ref'

After running script, I included that project to my solution as dependency and to all references collection when compiling I added Net50.All

I hope I helped you 😃

@tkw-devs - got it 👍 I manage to solve it! Thx!

Yes, it solved. Thank you