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