c# - 编辑并继续不适用于 Roslyn 编译的类库
问题描述
背景
我正在尝试让 Edit and Continue 使用我在运行时使用 Roslyn 编译的类库。这是为我正在开发的游戏添加修改支持。
问题分解
- 我有一个带有源文件(.cs)的类库项目(A)
- 我在另一个解决方案中有另一个控制台应用程序项目 (B),它执行以下操作:
- 编译项目 A 的所有源文件
- 发出 dll 和 pdb
- 通过程序集上下文加载发出的 dll 和 pdb
- 调用项目 B 中定义的静态方法
- 我的愿望是能够在加载了项目 A 的 VS 实例中将调试器附加到项目 B 的运行进程,并且能够中断、编辑项目 A 的代码,并继续执行我的更改
- 目前,我只能打破并继续
- 任何编辑都会导致以下通知:
此源文件已更改。它不再与用于构建正在调试的应用程序的文件版本匹配。
资源
项目 A:DebuggableClassLibrary.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
</Project>
项目 A:Test.cs
using System;
namespace DebuggableClassLibrary
{
public class Test
{
public static int Ct = 0;
public static void SayHello()
{
Ct++;
Console.WriteLine("Hello World");
}
}
}
项目 B:DynamicLoading.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" />
</ItemGroup>
</Project>
项目 B:Program.cs
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
namespace DynamicLoading
{
class Program
{
static void Main(string[] args)
{
var references = new MetadataReference[]
{
MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location),
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Console).Assembly.Location)
};
var files = Directory.GetFiles(@"C:\Users\mrbri\source\repos\DebuggableClassLibrary\DebuggableClassLibrary", "*.cs");
var assemblyName = "DebuggableClassLibrary.dll";
var debug = true;
var allowUnsafe = false;
var outputDirectory = @"C:\Users\mrbri\Documents\Test";
var preprocessorSymbols = debug ? new string[] { "DEBUG" } : new string[] { };
var parseOptions = new CSharpParseOptions(LanguageVersion.Latest, preprocessorSymbols: preprocessorSymbols);
var compilation = CSharpCompilation.Create(
assemblyName: assemblyName,
syntaxTrees: files.Select(f => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f), parseOptions, f, Encoding.UTF8)),
references: references,
options: new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default,
optimizationLevel: debug ? OptimizationLevel.Debug : OptimizationLevel.Release,
allowUnsafe: allowUnsafe
));
var pePath = Path.Combine(outputDirectory, assemblyName);
var pdbPath = Path.Combine(outputDirectory, Path.ChangeExtension(assemblyName, ".pdb"));
using (var peStream = new FileStream(pePath, FileMode.Create))
using (var pdbStream = new FileStream(pdbPath, FileMode.Create))
{
var results = compilation.Emit(
peStream: peStream,
pdbStream: pdbStream,
options: new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb)
);
}
var assemblyLoadContext = new SimpleUnloadableAssemblyLoadContext();
var assembly = assemblyLoadContext.LoadFromStream(File.OpenRead(pePath), File.OpenRead(pdbPath));
var type = assembly.GetTypes().First();
var method = type.GetMethod("SayHello");
while (true)
{
method.Invoke(null, null);
}
}
}
internal class SimpleUnloadableAssemblyLoadContext : AssemblyLoadContext
{
public SimpleUnloadableAssemblyLoadContext(): base(true) { }
protected override Assembly Load(AssemblyName assemblyName) => null;
}
}
尝试解决方案和观察
- 通过 VS 手动编译项目 A 并完全像我为 Roslyn 编译的那样加载生成的 pdb 和 dll 确实允许编辑并继续
- 在 JetBrains dotPeek 中比较通过 Roslyn 和 VS 生成的项目 A 的 dll 确实产生了一些有趣的差异,这些差异源于生成的编译时间
.NETCoreApp,Version=v5.0.AssemblyAttributes.cs
,并且DebuggableClassLibrary.AssemblyInfo.cs
我在项目 B 中编译时不包括在内 - 经历通过 MSBuildWorkspace 项目编译项目 A 的麻烦不允许编辑并继续,尽管确实包括
.NETCoreApp,Version=v5.0.AssemblyAttributes.cs
和DebuggableClassLibrary.AssemblyInfo.cs
备择方案
我对确实具有编辑和继续支持的 Roslyn 替代品/包装器持开放态度。
解决方案
编辑并继续不支持这种情况。正在编辑的库的项目需要在 VS 中加载(在当前解决方案中),并且需要在附加调试器的情况下启动程序。
推荐阅读
- angular - 如何在测试期间检查内部组件的方法被调用?
- java - 如何在 android studio 中将 Pagingnation 添加到 Recycleview
- c# - 为什么不能在析构函数中释放托管的东西?
- sql - 谷歌公开专利数据 SQL (BigQuery)
- windows - 批量重命名文件以删除文件名中间的前缀和字符
- python - VS 代码导入错误 原来的错误是:DLL load failed while importing _multiarray_umath: The specified module could not be found
- r - 访问 Blue Sky Statistics 版本 10(测试版)
- django - Django ListView 忽略 get_Queryset 中的 Order_by
- javascript - 不允许多个构造函数实现 - 只有一个构造函数?
- laravel - 在 Windows 10 上的 WindowsPipes.php 的第 71 行在 Laravel 中运行 composer install 时出错