RSCG – AspectGenerator
RSCG – AspectGenerator
name | AspectGenerator |
nuget | https://www.nuget.org/packages/AspectGenerator/ |
link | https://github.com/igor-tkachev/AspectGenerator |
author | Igor Tkachev |
AOP for methods in the same project. Uses interceptors
This is how you can use AspectGenerator .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <PackageReference Include="AspectGenerator" Version="0.0.9-preview" OutputItemType="Analyzer" /> </ItemGroup> <PropertyGroup> <InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);AspectGenerator</InterceptorsPreviewNamespaces> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> </PropertyGroup> </Project>
The code that you will use is
using AG; var p=new Person { FirstName="Ignat", LastName="Andrei" }; var x= p.FullName(); Console.WriteLine(x);
namespace AG; internal class Person { public string? FirstName { get; set; } public string? LastName { get; set; } [Metrics] public string FullName() { return $"{FirstName} {LastName}"; } }
using System.Diagnostics; using AspectGenerator; namespace AG; [Aspect( // Specify the name of the method used in the 'using' statement // that returns an IDisposable object. OnUsing = nameof(OnUsing) )] [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] sealed class MetricsAttribute : Attribute { //static readonly ActivitySource _activitySource = new("Sample.Aspect"); public static Activity? OnUsing(InterceptInfo info) { Console.WriteLine($"Entering {info.MemberInfo.Name}"); return null; //var data=_activitySource.StartActivity(info.MemberInfo.Name); //return data; } }
The code that is generated is
// <auto-generated/> #pragma warning disable #nullable enable using System; #if AG_GENERATE_API || !AG_NOT_GENERATE_API namespace AspectGenerator { /// <summary> /// <para>Defines an aspect.</para> /// <para>Create a new attribute decorated with this attribute to define an aspect.</para> /// </summary> [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] #if AG_PUBLIC_API public #endif sealed class AspectAttribute : Attribute { public string? OnInit { get; set; } public string? OnUsing { get; set; } public string? OnUsingAsync { get; set; } public string? OnBeforeCall { get; set; } public string? OnBeforeCallAsync { get; set; } public string? OnCall { get; set; } public string? OnAfterCall { get; set; } public string? OnAfterCallAsync { get; set; } public string? OnCatch { get; set; } public string? OnCatchAsync { get; set; } public string? OnFinally { get; set; } public string? OnFinallyAsync { get; set; } public string[]? InterceptMethods { get; set; } public bool UseInterceptType { get; set; } public bool PassArguments { get; set; } public bool UseInterceptData { get; set; } } #if AG_PUBLIC_API public #endif enum InterceptType { OnInit, OnUsing, OnBeforeCall, OnAfterCall, OnCatch, OnFinally } #if AG_PUBLIC_API public #endif enum InterceptResult { Continue, Return, ReThrow = Continue, IgnoreThrow = Return } #if AG_PUBLIC_API public #endif struct Void { } #if AG_PUBLIC_API public #endif partial class InterceptInfo { public object? Tag; public InterceptType InterceptType; public InterceptResult InterceptResult; public Exception? Exception; public InterceptInfo? PreviousInfo; public System.Reflection.MemberInfo MemberInfo; public object?[]? MethodArguments; public Type AspectType; public System.Collections.Generic.Dictionary<string,object?> AspectArguments; } #if AG_PUBLIC_API public #endif partial class InterceptInfo<T> : InterceptInfo { public T ReturnValue; } #if AG_PUBLIC_API public #endif partial struct InterceptData<T> { public object? Tag; public InterceptType InterceptType; public InterceptResult InterceptResult; public Exception? Exception; public InterceptInfo<T>? PreviousInfo; public System.Reflection.MemberInfo MemberInfo; public object?[]? MethodArguments; public Type AspectType; public System.Collections.Generic.Dictionary<string,object?> AspectArguments; public T ReturnValue; } } #endif #if AG_GENERATE_InterceptsLocationAttribute || !AG_NOT_GENERATE_InterceptsLocationAttribute namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] sealed class InterceptsLocationAttribute(string filePath, int line, int character) : Attribute { } } #endif
// <auto-generated/> #pragma warning disable #nullable enable using System; using SR = System.Reflection; using SLE = System.Linq.Expressions; using SCG = System.Collections.Generic; namespace AspectGenerator { using AspectGenerator = AspectGenerator; static partial class Interceptors { static SR.MethodInfo GetMethodInfo(SLE.Expression expr) { return expr switch { SLE.MethodCallExpression mc => mc.Method, _ => throw new InvalidOperationException() }; } static SR.MethodInfo MethodOf<T>(SLE.Expression<Func<T>> func) => GetMethodInfo(func.Body); static SR.MethodInfo MethodOf (SLE.Expression<Action> func) => GetMethodInfo(func.Body); static SR. MemberInfo FullName_Interceptor_MemberInfo = MethodOf(() => default(AG.Person).FullName()); static SCG.Dictionary<string,object?> FullName_Interceptor_AspectArguments_0 = new() { }; // /// <summary> /// Intercepts AG.Person.FullName(). /// </summary> // // Intercepts p.FullName(). [System.Runtime.CompilerServices.InterceptsLocation(@"D:\gth\RSCG_Examples\v2\rscg_examples\AspectGenerator\src\AG\Program.cs", line: 4, character: 10)] // [System.Runtime.CompilerServices.CompilerGenerated] //[System.Diagnostics.DebuggerStepThrough] public static string FullName_Interceptor(this AG.Person __this__) { // AG.MetricsAttribute // var __info__0 = new AspectGenerator.InterceptInfo<string> { MemberInfo = FullName_Interceptor_MemberInfo, AspectType = typeof(AG.MetricsAttribute), AspectArguments = FullName_Interceptor_AspectArguments_0, }; using (AG.MetricsAttribute.OnUsing(__info__0)) { __info__0.ReturnValue = __this__.FullName(); } return __info__0.ReturnValue; } } }
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/AspectGenerator
Leave a Reply