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