Roslyn не имеет ссылки на System.Runtime

Я работаю над проектом, в котором мы используем Roslyn для компиляции некоторых шаблонов для нас. Теперь, когда я компилирую шаблон, я получаю несколько ошибок в CompileResult.Diagnostics.

Ошибки:

(21,6): error CS0012: The type 'System.Attribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
(21,6): error CS0012: The type 'System.Type' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

Увидев эти ошибки, я предположил, что я не добавил ссылку на сборку System.Runtime правильно. Однако после проверки загруженных сборок это выглядит в порядке.

private IEnumerable<MetadataReference> GetGlobalReferences()
{
    var assemblies = new [] 
        {
            typeof(System.Object).Assembly,                         //mscorlib
            typeof(System.Composition.ExportAttribute).Assembly,    //System.Composition (MEF)
            typeof(System.CodeDom.Compiler.CodeCompiler).Assembly,  //System.CodeDom.Compiler
        };

    var refs = from a in assemblies
                select new MetadataFileReference(a.Location);

    return refs.ToList();
}

И сама компиляция:

public void Compile(AssemblyFileInfo assemblyInfo)
{
    Parse(assemblyInfo.Files);

    var compilation = CSharpCompilation.Create(assemblyInfo.FilePath, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
                        .AddReferences(GetGlobalReferences())
                        .AddSyntaxTrees(assemblyInfo.SourceCodeSyntaxTrees);

    assemblyInfo.CompileResult = compilation.Emit(assemblyInfo.FilePath);
}

Я пропустил что-то очевидное? Похоже, что все предпосылки для успешной компиляции выполнены, но, по-видимому, это не так.

Для справки, это (обфускация) часть кода, которую я пытаюсь скомпилировать:

namespace Project.Rules.Generated
{
    using System;
    using System.Runtime;
    using System.Composition;
    using System.CodeDom.Compiler;

    [Export(typeof(IProject))]
    [GeneratedCode("Project Template Compiler", "1.0")]
    public sealed class ProcessPriorityValue : ProjectConcreteClass
    {
        public override void Execute(ProjectExecutionContext ctx)
        {
            CurrentContext = ctx;
        }
    }
}

изменить Я немного продвинулся в своих поисках. PublicKeyToken, указанный в сообщениях об ошибках, соответствует сборке PublicKeyToken в сборках System.Composition. Мое предположение заключалось в том, что добавление всех сборок могло решить проблему. Это правильно или, по крайней мере, часть решения. Используя dotPeek, я смог проверить, какие объекты существуют в разных сборках. Благодаря этим знаниям я изменил метод GetGlobalReferences() на это:

private IEnumerable<MetadataReference> GetGlobalReferences()
{
    var assemblies = new [] 
        {
            typeof(System.Object).Assembly,                                     //mscorlib
            typeof(System.Composition.ExportAttribute).Assembly,                //System.Composition.AttributeModel
            typeof(System.Composition.Convention.ConventionBuilder).Assembly,   //System.Composition.Convention
            typeof(System.Composition.Hosting.CompositionHost).Assembly,        //System.Composition.Hosting
            typeof(System.Composition.CompositionContext).Assembly,             //System.Composition.Runtime
            typeof(System.Composition.CompositionContextExtensions).Assembly,   //System.Composition.TypedParts
            typeof(System.CodeDom.Compiler.CodeCompiler).Assembly,              //System.CodeDom.Compiler
        };

    var refs = from a in assemblies
                select new MetadataFileReference(a.Location);

    return refs.ToList();
}

Как вы можете видеть, я добавляю все сборки System.Composition теперь, указав объект, который существует в сборке. Добавив System.Composition.Runtime, мои ошибки компиляции решались.

Однако это привело к другой ошибке. Как вы можете проверить себя, есть общий класс экспорта в System.Composition.Runtime: public sealed class Export<T> : IDisposable Из-за этого я получаю эту ошибку:

(21,6): error CS0404: Cannot apply attribute class 'System.Composition.Export<T>' because it is generic

По какой-то причине код теперь хочет использовать System.Composition.Runtime.Export<T>, а не ExportAttribute, определенный в System.Composition.AttributeModel сборке.

edit2

Я могу подтвердить, что приведенный выше код использует System.Composition.Export<T>, а не ExportAttribute. Я обнаружил это, изменив [Export(typeof(IProject)] на [ExportAttribute(typeof(IProject)]. Из-за этого изменения возвращаются исходные ошибки. Похоже, что сборка System.Composition.AttributeModel не загружена/правильно указана, но после проверки compilation я вижу, что на сборку ссылаются нормально.

Ссылочные сборки, которые у меня есть на данный момент:

+       [0] mscorlib, Version=4.0.0.0, Culture=neutral, PublicKey=00000000000000000400000000000000  Microsoft.CodeAnalysis.AssemblyIdentity
+       [1] System.Composition.AttributedModel, Version=1.0.20.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293   Microsoft.CodeAnalysis.AssemblyIdentity
+       [2] System.Composition.Convention, Version=1.0.20.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293    Microsoft.CodeAnalysis.AssemblyIdentity
+       [3] System.Composition.Hosting, Version=1.0.20.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293   Microsoft.CodeAnalysis.AssemblyIdentity
+       [4] System.Composition.Runtime, Version=1.0.20.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293   Microsoft.CodeAnalysis.AssemblyIdentity
+       [5] System.Composition.TypedParts, Version=1.0.20.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293    Microsoft.CodeAnalysis.AssemblyIdentity
+       [6] Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293  Microsoft.CodeAnalysis.AssemblyIdentity
+       [7] System, Version=4.0.0.0, Culture=neutral, PublicKey=00000000000000000400000000000000    Microsoft.CodeAnalysis.AssemblyIdentity
+       [8] System.Core, Version=4.0.0.0, Culture=neutral, PublicKey=00000000000000000400000000000000   Microsoft.CodeAnalysis.AssemblyIdentity
+       [9] System.Data, Version=4.0.0.0, Culture=neutral, PublicKey=00000000000000000400000000000000   Microsoft.CodeAnalysis.AssemblyIdentity

Ответы

Ответ 1

По запросу Деяна в разделе комментариев я выложу ответ (на мою проблему) как реальный ответ.


Я выяснил, в чем проблема! Компилятор был верен все время. Сообщение в блоге smack0007 заставило меня попробовать что-то еще. Вместо того, чтобы использовать Фасадную DLL, попробуйте ссылаться на необходимую DLL вручную. Метод GetGlobalReferences теперь выглядит так:

private IEnumerable<MetadataReference> GetGlobalReferences()
{
    var assemblies = new [] 
        {
            /*Making sure all MEF assemblies are loaded*/
            typeof(System.Composition.Convention.AttributedModelProvider).Assembly, //System.Composition.AttributeModel
            typeof(System.Composition.Convention.ConventionBuilder).Assembly,   //System.Composition.Convention
            typeof(System.Composition.Hosting.CompositionHost).Assembly,        //System.Composition.Hosting
            typeof(System.Composition.CompositionContext).Assembly,             //System.Composition.Runtime
            typeof(System.Composition.CompositionContextExtensions).Assembly,   //System.Composition.TypedParts

            /*Used for the GeneratedCode attribute*/
            typeof(System.CodeDom.Compiler.CodeCompiler).Assembly,              //System.CodeDom.Compiler
        };

    var refs = from a in assemblies 
                select new MetadataFileReference(a.Location);
    var returnList = refs.ToList();

    //The location of the .NET assemblies
    var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);

    /* 
        * Adding some necessary .NET assemblies
        * These assemblies couldn't be loaded correctly via the same construction as above,
        * in specific the System.Runtime.
        */
    returnList.Add(new MetadataFileReference(Path.Combine(assemblyPath, "mscorlib.dll")));
    returnList.Add(new MetadataFileReference(Path.Combine(assemblyPath, "System.dll")));
    returnList.Add(new MetadataFileReference(Path.Combine(assemblyPath, "System.Core.dll")));
    returnList.Add(new MetadataFileReference(Path.Combine(assemblyPath, "System.Runtime.dll")));

    return returnList;
}

При декомпиляции System.Runtime.dll я также понял, почему на него нельзя ссылаться каким-либо другим способом. DLL пуста, она содержит только некоторые ссылки на другие сборки. Поэтому нельзя ссылаться на эту сборку иначе.

Ответ 2

Похоже, вы ссылаетесь на PortableClassLibrary. Портативные библиотеки классов выбирают некоторые из основных типов (например, object/string/etc) из "System.Runtime.dll". Тем не менее, в среде рабочего стола это происходит из mscorlib.dll. Когда вы используете typeof(object).Assembly, вы получаете собственную версию Roslyn object. Поскольку Roslyn не построен в виде переносных библиотек классов, это тот, который из mscorlib, и не соответствует личность ваших других ссылок.