.net 8 如何让指定的类可以在 AOT 模式下应用反射

方式一

让类库指定的类支持反射

在类库中编写一个静态类 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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值