源生成器在启动过程中导致typeeloadeexception



我正在一个。net 7项目中工作,我正在使用正则表达式解析日志文件。我有几个带有正则表达式的类,它们尝试解析一行文本,如果成功,则返回该类的一个实例,并填充其属性。创建一个新类、所有属性和一个静态解析函数(此时基本上是样板文件)变得越来越乏味。所以,我试图创建一个源生成器,查找类使用正则表达式的属性类。我已经达到了生成一个满足我的要求并编译的有效文件的地步。

但是当我尝试运行程序时,我得到一个System.TypeLoadException异常。

我已经尝试清理解决方案并删除binobj文件夹,但在启动期间我仍然得到相同的异常。如果我将源生成器的输出复制到项目中,而不触发源生成器,那么它会正常工作,它会到达我的主函数并使用生成的解析器,而不会出现任何问题。我甚至能够使用IL-Spy来反编译。dll,从命令行重新编译,并成功运行它。

以下是VS 2022的调试输出:

'ScheduleLogParser.exe' (CoreCLR: DefaultDomain): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Private.CoreLib.dll'. Symbols loaded.
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Users_______sourcereposScheduleLogParserScheduleLogParserbinDebugnet7.0ScheduleLogParser.dll'. Symbols loaded.
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Runtime.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'c:program filesmicrosoft visual studio2022communitycommon7idecommonextensionsmicrosofthotreloadMicrosoft.Extensions.DotNetDeltaApplier.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.IO.Pipes.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Linq.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Collections.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Console.dll'. Symbols loaded.
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Threading.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Runtime.InteropServices.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Threading.Overlapped.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Security.AccessControl.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Security.Principal.Windows.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Security.Claims.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Runtime.Loader.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Collections.Concurrent.dll'. 
An unhandled exception of type 'System.TypeLoadException' occurred in Unknown Module.
Failure has occurred while loading a type.
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Diagnostics.StackTrace.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Reflection.Metadata.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Collections.Immutable.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.IO.MemoryMappedFiles.dll'. 
'ScheduleLogParser.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App7.0.4System.Text.Encoding.Extensions.dll'. 
The program '[39096] ScheduleLogParser.exe' has exited with code 0 (0x0).

这是源代码生成器。csproj:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>11.0</LangVersion>
<Nullable>enable</Nullable>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<IncludeBuildOutput>false</IncludeBuildOutput>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<None Include="$(OutputPath)$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
</Project>

这里是消费者。csproj:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..ScheduleLogParser.ParserGenerator.AttributesScheduleLogParser.ParserGenerator.Attributes.csproj" />
<ProjectReference Include="..ScheduleLogParser.ParserGeneratorScheduleLogParser.ParserGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>

这是ISourceGenerator:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using System.Text;
using System;
namespace ScheduleLogParser.ParserGenerator;
[Generator]
public sealed class SourceGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
// Register a syntax receiver that will be created for each generation pass
context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
// retrieve the populated receiver 
if (context.SyntaxContextReceiver is not SyntaxReceiver receiver)
return;
foreach (var workItem in receiver.WorkItems)
{
context.AddSource($"{workItem.ParserClass.FullName()}.g.cs", ClassGenerator.GenerateClass(workItem));
}

//Write the log entries
context.AddSource("Logs", SourceText.From($"/*nGenerated: {DateTime.Now}n{string.Join("n", receiver.Log)}n*/", Encoding.UTF8));
}
}

源类:

namespace ScheduleLogParser.Parsers;
/* language=regex */
[ParserGenerator(@"^(?<TimeOnly_TimeStamp>dd:dd:dd)s+Checking stocked material constraint for operation (?<int_OprSeq>d+) material (?<string_MtlPartNum>.+?) for (?<DateOnly_CheckingDate>d{1,2}/d{1,2}/d{4}). --- (?<string_Method>w+)$")]
public sealed partial class CheckingStockedMaterial : ILogLineParser<CheckingStockedMaterial>
{
}

生成的文件如下:

using System;
using System.Text.RegularExpressions;
namespace ScheduleLogParser.Parsers;
public sealed partial class CheckingStockedMaterial : ScheduleLogParser.Parsers.ILogLineParser<ScheduleLogParser.Parsers.CheckingStockedMaterial>, ScheduleLogParser.Parsers.ILogLineParser
{
private static readonly Regex _regex = new(@"^(?<TimeOnly_TimeStamp>dd:dd:dd)s+Checking stocked material constraint for operation (?<int_OprSeq>d+) material (?<string_MtlPartNum>.+?) for (?<DateOnly_CheckingDate>d{1,2}/d{1,2}/d{4}). --- (?<string_Method>w+)$");
public int LineNumber { get; private init; }
public TimeOnly TimeStamp { get; private init; }
public int OprSeq { get; private init; }
public string MtlPartNum { get; private init; }
public DateOnly CheckingDate { get; private init; }
public string Method { get; private init; }
public static CheckingStockedMaterial? Parse(string line, int lineNumber)
{
var match = _regex.Match(line);
return match.Success == true ?
new CheckingStockedMaterial
{
LineNumber = lineNumber,
TimeStamp = TimeOnly.Parse(match.Groups["TimeOnly_TimeStamp"].ValueSpan),
OprSeq = int.Parse(match.Groups["int_OprSeq"].ValueSpan),
MtlPartNum = match.Groups["string_MtlPartNum"].Value,
CheckingDate = DateOnly.Parse(match.Groups["DateOnly_CheckingDate"].ValueSpan),
Method = match.Groups["string_Method"].Value
} : null;
}
}
  1. 输出与<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>。检查文件,你可以将它们复制到你的解决方案中,并运行控制台应用程序,而不需要生成器。
  2. 如果你计划在。net及以后的项目中使用generator,请尝试切换到所需的最小版本。本例为Microsoft.CodeAnalysis.CSharpv4.4.0。
  3. 使用IIncrementalGenerator作为生成器
  4. 使用ForAttributeWithMetadataName在源代码中搜索属性。