目录
方式一
让类库指定的类支持反射
在类库中编写一个静态类 Aot.cs
public class Aot
{
public static void Init()
{
int c = 0;
if (c == 1)
return;
typeof(Class1).GetMembers();
typeof(Class2).GetConstructors();
}
}
上段代码,我分别指定了Class1可以反射所有成员,Class2可以反射构造函数。
然后创建一个控制台项目,引用这个类库,并在 main 函数任意位置,调用一下 Aot.Init()
namespace ConsoleApp8
{
internal class Program
{
static void Main(string[] args)
{
Aot.Init();
}
}
}
虽然 Aot.Init 没有执行任何代码,但是却让编译器能识别出Class1和Class2在反射中要使用哪些成员。
让整个程序集都可以反射
假如你要发布的是一个控制台项目,那么在项目中创建 rd.xml 文件,内容如下:
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Application>
<Assembly Name="ClassLibrary1">
<Type Name="ClassLibrary1.Class2" Dynamic="Required All"></Type>
</Assembly>
<Assembly Name="ClassLibrary2" Dynamic="Required All"></Assembly>
</Application>
</Directives>
让 ClassLibrary1 程序集中的 Class2 类和 ClassLibrary2 程序集所有类都可以进行反射。
在工程 .csproj 中,加入:
<ItemGroup>
<RdXmlFile Include="rd.xml" />
</ItemGroup>
方式二、用源生成器自动生成分析代码
先创建一个类库项目,添加一个类:
namespace AOTReflectionHelper
{
[AttributeUsage(AttributeTargets.Class)]
public partial class AOTReflectionAttribute : Attribute
{
}
}
再创建一个netstandard2.0的项目(必须是netstandard2.0,否则不起作用)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>12.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0-beta1.23525.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0-2.final" />
</ItemGroup>
</Project>
并创建这样一个类:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Text;
namespace AOTReflectionGenerator
{
[Generator]
public class AOTReflectionGenerator : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
var types = GetAOTReflectionAttributeTypeDeclarations(context);
var source = BuildSourse(types);
context.AddSource($"AOTReflectionGenerator.g.cs", source);
}
string BuildSourse(IEnumerable<(string NamespaceName, string ClassName)> types)
{
var codes = new StringBuilder();
foreach (var type in types)
{
codes.AppendLine($" typeof({(type.NamespaceName != "<global namespace>" ? type.NamespaceName + "." : "")}{type.ClassName}).GetMembers();");
}
var source = $$"""
using System;
[AttributeUsage(AttributeTargets.Class)]
public partial class AOTReflectionAttribute:Attribute
{
public AOTReflectionAttribute()
{
{{codes}}
}
}
""";
return source;
}
IEnumerable<(string NamespaceName, string ClassName)> GetAOTReflectionAttributeTypeDeclarations(GeneratorExecutionContext context)
{
var list = new List<(string, string)>();
foreach (var tree in context.Compilation.SyntaxTrees)
{
var semanticModel = context.Compilation.GetSemanticModel(tree);
var root = tree.GetRoot(context.CancellationToken);
var typeDecls = root.DescendantNodes().OfType<TypeDeclarationSyntax>();
foreach (var decl in typeDecls)
{
// 获取类型的语义模型
var symbol = semanticModel.GetDeclaredSymbol(decl);
// 检查类型是否带有 AOTReflectionAttribute 特性
if (symbol?.GetAttributes().Any(attr => attr.AttributeClass?.Name == "AOTReflectionAttribute") == true)
{
// 处理带有 AOTReflectionAttribute 特性的类型
var className = decl.Identifier.ValueText;
var namespaceName = symbol.ContainingNamespace?.ToDisplayString();
list.Add((namespaceName, className));
}
}
}
return list;
}
public void Initialize(GeneratorInitializationContext context)
{
}
}
}
在需要进行AOT编译的项目上,引用上面两个项目:
<ItemGroup>
<ProjectReference Include="..\AOTReflectionGenerator\AOTReflectionGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
<ProjectReference Include="..\AOTReflectionHelper\AOTReflectionHelper.csproj" />
</ItemGroup>
哪个类需要保留反射功能,就给它加上一个 [AOTReflection] 特性即可。
发布注意事项
建议使用 dotnet publish -c Release -r win-x64 /p:PublishAot=true 发布工程,
不要直接在工程上设置:
<PublishAot>true</PublishAot>
因为这样会让例如 Avalonia 等类库在设计时报错。
json需要添加设置JsonSerializerIsReflectionEnabledByDefault
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
</Project>