File: System\Resources\Tools\CodeDomCompileHelper.cs
Web Access
Project: src\src\System.Windows.Forms.Design\tests\UnitTests\System.Windows.Forms.Design.Tests.csproj (System.Windows.Forms.Design.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.CodeDom.Compiler;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CSharp;
using System.CodeDom;
using System.Runtime.Loader;
using System.Reflection;
using System.Drawing;
 
namespace System.Resources.Tools.Tests;
 
internal static class CodeDomCompileHelper
{
    private static readonly CodeDomProvider s_cSharpProvider = new CSharpCodeProvider();
 
    private static MetadataReference[] References { get; } = CreateReferences();
 
    private static MetadataReference[] CreateReferences()
    {
        string corelibPath = typeof(object).Assembly.Location;
        return new[]
        {
            MetadataReference.CreateFromFile(corelibPath),
            MetadataReference.CreateFromFile(Path.Join(Path.GetDirectoryName(corelibPath), "System.Runtime.dll")),
            MetadataReference.CreateFromFile(typeof(Bitmap).Assembly.Location),
        };
    }
 
    private static Stream CreateAssemblyImage(string source, string assemblyName, string resourceName, Stream resource)
    {
        CSharpCompilation compilation = CSharpCompilation.Create(
            assemblyName,
            new[] { CSharpSyntaxTree.ParseText(source) },
            References,
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
 
        ResourceDescription[] description = resource is null
            ? null
            : [new(resourceName, () => resource, isPublic: true)];
 
        MemoryStream stream = new();
        var result = compilation.Emit(stream, manifestResources: description);
        if (result.Success)
        {
            stream.Position = 0;
            return stream;
        }
        else
        {
            throw new InvalidOperationException(string.Join('\n', result.Diagnostics.Select(d => d.GetMessage())));
        }
    }
 
    internal static Type CompileClass(
        CodeCompileUnit compileUnit,
        string baseName,
        string nameSpace = null,
        Stream resource = null)
    {
        AssemblyLoadContext context = new(name: null, isCollectible: true);
        string fullName = nameSpace is null ? baseName : $"{nameSpace}.{baseName}";
 
        using StringWriter writer = new();
        s_cSharpProvider.GenerateCodeFromCompileUnit(compileUnit, writer, new());
        Assembly assembly = context.LoadFromStream(CreateAssemblyImage(
            writer.ToString(),
            fullName,
            $"{fullName}.resources",
            resource));
        Type type = assembly.GetType(fullName, throwOnError: true);
 
        // Once all references are collected, the assembly will unload.
        context.Unload();
        return type;
    }
}