.Net Core - CS0012 'Object' 在未引用的程序集中定义

.Net Core - CS0012 'Object' is defined in an assembly that is not referenced

我是 .Net Core 的新手,我正在尝试基于它构建构建系统。作为这个项目的一部分,我创建了一个摘要 class 来阐明构建任务应该实现什么,并且我已经将它塞进了一个共享库中。

可执行项目引用此库并扫描项目目录以查找特殊命名的目录,然后检查其中是否有任何 .cs 文件。加载这些脚本,然后尝试使用 Microsoft.CodeAnalysis 和朋友提供的工具进行编译。

在这种背景下,我在编译阶段遇到了一个奇怪的问题:

如果我尝试将包含摘要 class 的共享库作为参考提供给编译过程,我会收到以下错误:

Failed CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'.

接着是一堆关于预定义类型的抱怨:

CS0518: Predefined type 'System.Boolean' is not defined or imported CS0518: Predefined type 'System.Boolean' is not defined or imported CS0518: Predefined type 'System.Void' is not defined or imported ... etc etc.

但是,如果我省略引用,而是将每个共享库的源文件解析为语法树并将它们传递给编译过程,那么整个过程都会成功,并且我会得到一个返回的内存中程序集,我可以提取类型出来并实例化。

我已经阅读了 Google 必须提供的有关此错误的所有内容,但我不知所措。有人可以告诉我为什么会发生这种情况,并为我如何实现最初的目标(简单地链接到一个公共共享库中)提供额外的互联网积分吗?

相关代码

    CSharpParseOptions parseOptions = CSharpParseOptions.Default;

    SyntaxTree jobSyntaxTree = CSharpSyntaxTree.ParseText(scriptContents, parseOptions);

    string generatedAssemblyName = Path.GetRandomFileName();
    var referencedAssemblies = Assembly.GetEntryAssembly().GetReferencedAssemblies();

    foreach(var referencedAssembly in referencedAssemblies)
    {
        var rfas = Assembly.Load(referencedAssembly);
        references.Add(MetadataReference.CreateFromFile(rfas.Location)); 
    }

    var op = new  CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);

    CSharpCompilation compilation = CSharpCompilation.Create(
       generatedAssemblyName,
       syntaxTrees: new[] { jobSyntaxTree },
       references: references,
       options: op);

    var ms = new MemoryStream();

    EmitOptions emitOptions = new EmitOptions();

    EmitResult result = compilation.Emit(ms);

    if(result.Success)
    {
       // Yay
    }
    else
    {
       // Boo-hoo
    }

Project.json 共享库文件

{
    "title": "BuildBotCore",
    "version": "1.0.0-*",
    "buildOptions": {
        "emitEntryPoint": false,
        "preserveCompilationContext": true
    },
    "dependencies": {
        "Microsoft.NETCore.App": {
            "type": "platform",
            "version": "1.0.0"
        },
        "System.Runtime": "4.1.0",
        "System.Runtime.Loader": "4.0.0",
        "Microsoft.NETCore.Portable.Compatibility": "1.0.1"
    },
    "frameworks": {
        "netcoreapp1.0": {
            "imports": "netcore50",
            "buildOptions": {
                "preserveCompilationContext": true
            }
        }
    },
    "configurations": {
        "Debug": {
            "buildOptions": {
                "define": [
                    "DEBUG",
                    "TRACE"
                ],
                "optimize": false,
                "preserveCompilationContext": true
            }
        },
        "Release": {
            "buildOptions": {
                "define": [
                    "RELEASE",
                    "TRACE"
                ],
                "optimize": true,
                "preserveCompilationContext": true
            }
        }
    }
}

Project.json 用于主要可执行文件

{
    "version": "1.0.0-*",
    "buildOptions": {
        "emitEntryPoint": true,
        "preserveCompilationContext": true
    },
    "dependencies": {
        "Microsoft.NETCore.App": {
            "type": "platform",
            "version": "1.0.0"
        },
        "System.Runtime": "4.1.0",
        "Microsoft.CodeAnalysis.CSharp": "1.3.2",
        "System.Runtime.Loader": "4.0.0",
        "Microsoft.NETCore.Portable.Compatibility": "1.0.1",
        "BuildBotCore": "1.0.0-*"
    },
    "frameworks": {
        "netcoreapp1.0": {
            "imports": "netcore50",
            "buildOptions": {
                "preserveCompilationContext": true
            }
        }
    },
    "configurations": {
        "Debug": {
            "buildOptions": {
                "define": [
                    "DEBUG",
                    "TRACE"
                ],
                "optimize": false,
                "preserveCompilationContext": true
            }
        },
        "Release": {
            "buildOptions": {
                "define": [
                    "RELEASE",
                    "TRACE"
                ],
                "optimize": true,
                "preserveCompilationContext": true
            }
        }
    }
}

TL;DR
在一天结束时,您需要传递对 "mscorlib.dll" 及其私有变体的引用。这将使上述编译错误消失。这也是 .net 核心中的跨平台,因为我已经在 Linux 和 Windows.

上测试了这个解决方案

完整版和代码示例
由于我正在等待帐户删除,因此我将 post 最后一个答案。

解决方案是根据某些其他类型程序集的位置手动包含 mscorlib.dll。像这样:

// Get the directory of a core assembly. We need this directory to
// build out our platform specific reference to mscorlib. mscorlib
// and the private mscorlib must be supplied as references for
// compilation to succeed. Of these two assemblies, only the private
// mscorlib is discovered via enumerataing assemblies referenced by
// this executing binary.
var dd = typeof(Enumerable).GetTypeInfo().Assembly.Location;
var coreDir = Directory.GetParent(dd);            

List<MetadataReference> references = new List<MetadataReference>
{   
    // Here we get the path to the mscorlib and private mscorlib
    // libraries that are required for compilation to succeed.
    MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"),
    MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location)           
};

还有第二个 mscorelib,但它的名称以 "private" 为前缀。这是由执行程序集自动引用的,因此无需像上面那样手动生成其路径。

当您从正在执行动态代码编译的执行程序集中提取引用时,您将获得此私有 mscorlib。像这样:

// Enumerate all assemblies referenced by this executing assembly
// and provide them as references to the build script we're about to
// compile.
var referencedAssemblies = Assembly.GetEntryAssembly().GetReferencedAssemblies();
foreach(var referencedAssembly in referencedAssemblies)
{
    var loadedAssembly = Assembly.Load(referencedAssembly);   

    references.Add(MetadataReference.CreateFromFile(loadedAssembly.Location)); 
}

现在这些引用已经组装好,您可以简单地将它们传递给您的代码编译:

// Initialize the compilation with our options, references and the
// already parsed syntax tree of the build script.
CSharpCompilation compilation = CSharpCompilation.Create(
    generatedAssemblyName,
    syntaxTrees: new[] { jobSyntaxTree },
    references: references,
    options: op);           

// Compile and emit new assembly into memory.
var ms = new MemoryStream();
EmitResult result = compilation.Emit(ms);

...瞧,您可以在 .Net 核心中使用 Roslyn 跨平台动态编译代码。