c# - C# 9.0 源代码生成器 - 忽略具有特定属性的类编译
问题描述
问题:
我有一个源生成器类,它生成一个包含async
/await
关键字的代码,生成器还编译这个类:
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
[CompilerGenerated]
private sealed class <TestMethod>d__0 : IAsyncStateMachine
{
...
}
有没有办法忽略那些包含[CompilerGenerated]
属性的类?
更新:
这个问题是这个问题的后续:
问题:
尝试实现一个自动依赖注入注册器,我的约定非常严格,所以它会非常有用。
我在注册包含异步方法的类时遇到问题,容器似乎在注册类时针对这些方法。
关于该项目:
- Soruce 生成器是 netstandard2.0
- 模型和可执行文件是 net5.0
- 当方法不是异步时,一切正常
- 实际上并不需要 MetadataReference 我只是想避免针对这些的答案
TL;DL
一些复制错误:
- CS0103 当前上下文中不存在名称“d__0”
- CS0103 当前上下文中不存在名称“TestMethod”
- CS1525 无效的表达式术语 '<'
- CS1002 ; 预期的
编码:
源生成器项目:
namespace Test.Build.Tools
{
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
/// <summary>
/// Auto register source generator.
/// </summary>
[Generator]
public class AutoRegisterSourceGenerator : ISourceGenerator
{
/// <inheritdoc/>
public void Initialize(GeneratorInitializationContext context)
{
}
/// <inheritdoc/>
public void Execute(GeneratorExecutionContext context)
{
StringBuilder stringBuilder = new("namespace Test.Extensions.DependencyInjection\n"
+ "{\n"
+ " using System;\n"
+ " using System.Threading.Tasks;\n"
+ " using Microsoft.Extensions.DependencyInjection;\n");
List<string> namespaces = new();
string defaultPath = typeof(object).Assembly.Location.Replace("mscorlib", "{0}");
List<MetadataReference> references = new()
{
{ MetadataReference.CreateFromFile(string.Format(defaultPath, "System.Threading.Tasks")) }
};
var types = GetAllTypes(context.Compilation);
var neededTypes = types.Where(t =>
{
string @namespace = t.ContainingNamespace.ToString();
if (@namespace.Contains("Test")
&& !t.Interfaces.IsEmpty
&& t.TypeKind == TypeKind.Class)
{
namespaces.Add(t.ContainingNamespace.ToString());
namespaces.Add(t.Interfaces[0].ContainingNamespace.ToString());
return true;
}
return false;
}).ToList();
namespaces.Distinct().OrderBy(n => n.ToString()).ToList().ForEach(n => stringBuilder.Append($" using {n};\n"));
stringBuilder.Append(
" /// <summary>\n" +
" /// Service registrator class.\n" +
" /// </summary>\n" +
" public static class ServicesRegistrator\n" +
" {\n" +
" /// <summary>\n" +
" /// Register dependency injection instances.\n" +
" /// </summary>\n" +
" /// <param name=\"services\">Startup services.</param>\n" +
" /// <returns>The given <see cref=\"IServiceCollection\"/> instance.</returns>\n" +
" public static IServiceCollection RegisterDomainModel(this IServiceCollection services)\n" +
" {\n");
foreach (var type in neededTypes)
{
stringBuilder.Append($" services.AddScoped<I{type.Name}, {type.Name}>();");
stringBuilder.AppendLine();
}
stringBuilder.Append(" return services;\n" +
" }\n" +
" }\n" +
"}\n");
context.Compilation.AddReferences(references);
context.AddSource("ServicesRegistrator", SourceText.From(stringBuilder.ToString(), Encoding.UTF8));
}
IEnumerable<INamedTypeSymbol> GetAllTypes(Compilation compilation) =>
GetAllTypes(compilation.GlobalNamespace);
IEnumerable<INamedTypeSymbol> GetAllTypes(INamespaceSymbol @namespace)
{
foreach (var type in @namespace.GetTypeMembers())
foreach (var nestedType in GetNestedTypes(type))
yield return nestedType;
foreach (var nestedNamespace in @namespace.GetNamespaceMembers())
foreach (var type in GetAllTypes(nestedNamespace))
yield return type;
}
IEnumerable<INamedTypeSymbol> GetNestedTypes(INamedTypeSymbol type)
{
yield return type;
foreach (var nestedType in type.GetTypeMembers()
.SelectMany(nestedType => GetNestedTypes(nestedType)))
yield return nestedType;
}
}
}
模型项目:
namespace TestClasses
{
using System.Threading.Tasks;
public interface ITestClass
{
public Task TestMethod();
}
}
namespace TestClasses.Model
{
using System.Threading.Tasks;
public class TestClass : ITestClass
{
public async Task TestMethod()
{
await Task.CompletedTask;
}
}
}
可执行文件
using Executable;
Program.Rgister();
namespace Executable
{
using Microsoft.Extensions.DependencyInjection;
using Test.Extensions.DependencyInjection;
using TestClasses;
public class Program
{
public static void Rgister()
{
IServiceCollection services = new ServiceCollection();
services.RegisterDomainModel();
var x = services.BuildServiceProvider().GetRequiredService<ITestClass>();
x.TestMethod();
}
}
}
更新:
生成的代码:
namespace Test.Extensions.DependencyInjection
{
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using TestClasses;
using TestClasses.Model;
/// <summary>
/// Service registrator class.
/// </summary>
public static class ServicesRegistrator
{
/// <summary>
/// Register dependency injection instances.
/// </summary>
/// <param name="services">Startup services.</param>
/// <returns>The given <see cref="IServiceCollection"/> instance.</returns>
public static IServiceCollection RegisterDomainModel(this IServiceCollection services)
{
services.AddScoped<ITestClass, TestClass>();
return services;
}
}
}
解决方案
推荐阅读
- vba - 带有复制/粘贴和日期/时间戳的 VBA Vlookup
- python - 何时在 Django 的 save() 中使用 force_update?
- sorting - 在 Go 中按 v[i]/w[i] 对 i 的数组进行排序
- c# - 对存储库模式的理解混乱
- r - 根据向量的第一个字符在 R 中重新编码变量
- java - 如何使 Int 只接受整数?
- actions-on-google - 如何在 Webhook api.ai 中触发多个 Intent?
- solr - 如何在 Solr 中使用 jHiccup?
- pointers - Fortran 与 C 指针结构的互操作性
- sql - 在 SQL 中进行多个潜入连接的最佳方法是什么