我正在一个。net 7项目中工作,我正在使用正则表达式解析日志文件。我有几个带有正则表达式的类,它们尝试解析一行文本,如果成功,则返回该类的一个实例,并填充其属性。创建一个新类、所有属性和一个静态解析函数(此时基本上是样板文件)变得越来越乏味。所以,我试图创建一个源生成器,查找类使用正则表达式的属性类。我已经达到了生成一个满足我的要求并编译的有效文件的地步。
但是当我尝试运行程序时,我得到一个System.TypeLoadException
异常。
我已经尝试清理解决方案并删除bin
和obj
文件夹,但在启动期间我仍然得到相同的异常。如果我将源生成器的输出复制到项目中,而不触发源生成器,那么它会正常工作,它会到达我的主函数并使用生成的解析器,而不会出现任何问题。我甚至能够使用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;
}
}
- 输出与
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
。检查文件,你可以将它们复制到你的解决方案中,并运行控制台应用程序,而不需要生成器。 - 如果你计划在。net及以后的项目中使用generator,请尝试切换到所需的最小版本。本例为
Microsoft.CodeAnalysis.CSharp
v4.4.0。 - 使用
IIncrementalGenerator
作为生成器 - 使用
ForAttributeWithMetadataName
在源代码中搜索属性。