快乐地在AOT项目中用反射

文章讲述了在AOT项目中,通过源生成器技术处理反射的局限性,允许对特定类型使用反射,如获取带有AOTReflectionAttribute的类的成员。
摘要由CSDN通过智能技术生成

反射是.NET开发的利器,但对于AOT来说,因为Native编译,所以反射的功能基本在AOT编译的项目中失效。办法总比困难多,这么好的东西不能扔掉,下面是“尽量”可以使用反射的例子,为什么“尽量”,看完下面的案例我们再做说明。

在AOT项目中使用反射基本原理:利用源生成器,在build项目时,提前调用一下每个想要反射类型的GetMember。

1、首先创建项目AOTReflectionHelper,这个项目中只有一个类AOTRefectionAttribute,并且这个类是分部类。

using System;


namespace AOTReflectionHelper
{
    [AttributeUsage(AttributeTargets.Class)]
    public partial class AOTReflectionAttribute : Attribute
    {
    }
}

2、然后创建AOTReflectionGenerator项目,这是一个源生成器的项目,项目文件如下:

<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.9.0-2.final" />
  </ItemGroup>
</Project>

源生器的实现代码如下,基本思路就是要生成上面AOTRefectionAttribute类的分部类,并在构造函数中调用项目中所有上了这个特性的择射GetMembers方法,因为在构建时处用反射获以成员,这部分没有问题。

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)
        {
        }
    }
}

3、APITest项目是一个测试项目,项目文件如下,注意12行的源生器,要加两个属性。

<Project Sdk="Microsoft.NET.Sdk.Web">


  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
    <PublishAot>true</PublishAot>
  </PropertyGroup>


  <ItemGroup>
    <ProjectReference Include="..\AOTReflectionGenerator\AOTReflectionGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
    <ProjectReference Include="..\AOTReflectionHelper\AOTReflectionHelper.csproj" />
  </ItemGroup>
</Project>

下面是实现代码,只要给想要反射的类型加上[AOTReflection]即可,我们就能第25行的方法中使用GetProperties了,否则这个方法返回的是个空数组。

using System.Text.Json.Serialization;
using System.Text;
using APITest.Models;
using AOTReflectionHelper;


var builder = WebApplication.CreateSlimBuilder(args);


builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});


var app = builder.Build();
app.MapGet("/test", () =>
{
    var order = new Order { Name = "桂素伟", Age = 10, Birthday = DateTime.Now, Hobbies = new string[] { "足球", "代码" } };
    InvockMethod(order);
    return GetString(order);


});
app.MapPost("/test", (Person person) =>
{
    return GetString(person);
});
string GetString<T>(T t) where T : Parent
{
    var sb = new StringBuilder();
    var pros = typeof(T)?.GetProperties();
    foreach (var pro in pros)
    {      
        if (pro != null)
        {
            if (pro.PropertyType.IsArray)
            {
                var arr = pro.GetValue(t) as string[];
                sb.Append($"{pro?.Name}:{string.Join(",", arr)};");
            }
            else
            {
                sb.Append($"{pro?.Name}:{pro?.GetValue(t)};");
            }
        }
    }
    t.Print(sb.ToString());
    return sb.ToString();
}


void InvockMethod<T>(T t)
{
    var method = typeof(T)?.GetMethod("Print");
    method?.Invoke(t, new object[] { "用反射调用Print" });
}
app.Run();


[JsonSerializable(typeof(Person))]
[JsonSerializable(typeof(string[]))]
public partial class AppJsonSerializerContext : JsonSerializerContext
{
}
public partial class Parent
{
    public void Print(string content)
    {      
        Console.WriteLine($"反射类型名:{GetType().Name},Print参数:{content}");
    }
}


[AOTReflection]
public partial class Order : Parent
{
    public string Name { get; set; }
    public int Age { get; set; }
    public DateTime Birthday { get; set; }
    public string[] Hobbies { get; set; }
}


namespace APITest.Models
{
    [AOTReflection]
    public class Person : Parent
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public DateTime Birthday { get; set; }
        public string[] Hobbies { get; set; }


    }
}

下面是Get的结果:

f1636fde709c281a08680710c798f85d.png

下面是Post的结果:

e03edd544da0c935eca21bfbc752e265.png

如果你详细尝试了上面的代码,可能就会理解到“尽量”了,因为.NET的反射非常强大,而使用这个方法,只能解决自己定义的类型的反射,因为是通过硬编码的方式,给自定义类型添加[AOTReflection]来完成的。不过提供的这个思路,你可以找到你所反射类型的特征,来针对性的在源生器里调用GetMembers,这就你就不受限制了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: AOT是Ahead Of Time的缩写,意为预编译。WinForm是Windows Forms的简称,是一种用于Windows桌面应用程序开发的基于.NET框架的用户界面库。而AOT WinForm则是指使用预编译技术来加快WinForm应用程序的启动和执行速度。 以常规的编译方式,.NET应用程序通常需要在运行时对字节码进行JIT编译,这将导致启动时间和执行速度较慢。然而,AOT可以在应用程序打包时将所有字节码预先编译成本地机器代码,从而在运行时直接执行,这大大提高了程序的性能和响应速度。 在使用AOT WinForm时,开发者可以选择对整个应用程序或者部分组件(如DLL或EXE文件)进行预编译。虽然AOT编译可能需要更长的时间和更多的计算资源来完成,但通过减少JIT编译的时间和避免因为JIT编译而产生的性能损失,AOT可以为应用程序带来显著的优化效果。 总的来说,AOT WinForm是一种非常有用的优化技术,它可以提升WinForm应用程序的性能和响应速度,尤其是在需要处理较大数据量和复杂逻辑的情况下。 ### 回答2: AO.T是一家致力于培训人工智能人才的公司,其开发的AO.T Winform是一款基于.NET Framework技术的窗体应用程序。WINFORM是WINDOWS FORMS的缩写,指的是Windows桌面应用程序。具有易于编写和使用、可多种控件设计和使用和可快速开发的特点,适用于各细分行业。AO.T Winform实现了窗口设计中各控件的灵活布局和操作,它可以简化Windows应用程序开发过程,同时通过提供免费的软件授权来降低企业的成本。 AO.T Winform支持在Windows上开发GUI应用程序,并且由于采用.NET技术,因此它可以使用C#或VB.NET等编程语言进行开发。它也提供了一系列的用户界面的控件和容器,比如TextBox文本框、Button按钮、Label标签、ComboBox下拉菜单、DataGridView表格控件以及各种面板和容器来帮助用户快速开发完整的应用程序。 AO.T Winform对于初学者来说是一款非常好的学习工具。学生可以用它来学习GUI编程、面向对象编程、事件驱动等技术,还可以通过练习来提高自己的编程能力,以及掌握多种常用的技巧,例如自定义控件和定制窗口等。 总之,AO.T Winform是一款灵活、易于使用、快速开发的GUI工具,可以帮助企业降低开发成本,还能够帮助学生快速掌握GUI编程,提高自己的编程水平。 ### 回答3: AOI(自动光学检查)技术在现代制造业中被广泛使用,可以帮助生产厂家在制造过程中快速准确地检查电路板的质量,提高生产效率和质量。AOI技术依赖于高精度的图像分析算法,需要可靠的软件平台来实现。 AOT WinForm是一款专门为AOI应用开发的图形用户界面(GUI)开发工具。它提供了多种开发组件、图形控件和功能模块,可以快速构建高效的AOI检测软件。使用AOT WinForm,开发者可以轻松地实现各种检测算法,包括PCB元器件安装检测、焊点检测、短路检测、开路检测、电路板外形检测等。与传统的手工检测方式相比,AOT WinForm可以大大提高检测速度和精度,降低生产成本和人力投入。 AOT WinForm具有以下优点: 1. 可视化的设计界面:AOT WinForm提供了友好的可视化设计界面,不需要编写复杂的代码就可以创建出漂亮的GUI界面,可以大大提高开发效率。 2. 高效的算法库:AOT WinForm内置了丰富的图像处理和算法库,包括常用的图像变换、边缘提取、滤波等算法,可以快速实现多种电路板检测功能。 3. 全面的支持:AOT WinForm支持多种数据接口和格式,可以与各种数据源集成,包括网络摄像头、CCD相机、扫描仪等。 4. 易于维护和升级:由于AOT WinForm使用标准的.NET框架和C#语言,因此易于维护和升级,开发者可以根据需要自由扩展和修改代码。 总之,AOT WinForm是一个高效、可靠的AOI开发工具,可以帮助电路板制造商提高生产效率和质量,加快新产品上市时间,降低生产成本。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值