rksoftware

Visual Studio とか C# とかが好きです

C# 12 の新機能の確認 「 インターセプター 」

そろそろ C# 12 の時期なので予習を始めなければなりません。
今回は 「 インターセプター 」 を確認してみましょう。

■ インターセプター

github.com
C# 12 がまだプレビューだからという理由を超えて実験的機能という意味でのプレビュー機能。
メソッド呼び出しを別のメソッドに置き換える機能。使用時には .csproj に <Features>InterceptorsPreview</Features> 要素を追加する。

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <LangVersion>Preview</LangVersion>
    <Features>InterceptorsPreview</Features>
    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
  </PropertyGroup>

</Project>

また、使用の際に必要となる System.Runtime.CompilerServices.InterceptsLocationAttribute 属性が見つからずエラーになるので、使用時に属性を作ります。※この方法が正しいのか分かりませんが......
エラー CS0246 型または名前空間の名前 'InterceptsLocationAttribute' が見つかりませんでした (using ディレクティブまたはアセンブリ参照が指定されていることを確認してください)
エラー CS0246 型または名前空間の名前 'InterceptsLocation' が見つかりませんでした (using ディレクティブまたはアセンブリ参照が指定されていることを確認してください)

namespace System.Runtime.CompilerServices
{
    sealed class InterceptsLocationAttribute(string filePath, int line, int character) : Attribute { }
}

実際の動作確認コードは次のようになりました。

Class c = new() { Name = "Tokai" };
c.Method("Saitama");    // Method::Name = Tokai, param = Saitama
c.Method("Gunma");      // Interceptor1::Name = Tokai, param = Gunma
c.Method("Ibaraki");    // Interceptor2::Name = Tokai, param = Ibaraki

class Class
{
    public string Name { get; set; }
    public void Method(string param) => Console.WriteLine($"Method :: Name = {Name}, param = {param}");
}


// インターセプター
static class Interceptor
{
    // Program.cs の中の 3 行目、3 文字目から始まるメソッド呼び出し ( Method("Gunma") ) を置き換える
    // this 引数はメソッドの所属するオブジェクト、第 2 引数は置き換え元のメソッドの引数
    [System.Runtime.CompilerServices.InterceptsLocation(@"C:\Sample\cs12\ConsoleAppVSPreview\ConsoleAppVSPreview\Program.cs", line: 3, character: 3)] // refers to the call at (L1, C1)
    public static void InterceptorMethod1(this Class c, string param) => Console.WriteLine($"Interceptor1 :: Name = {c.Name}, param = {param}");

    // Program.cs の中の 4 行目、3 文字目から始まるメソッド呼び出し ( Method("Ibaraki") ) を置き換える
    [System.Runtime.CompilerServices.InterceptsLocation(@"C:\Sample\cs12\ConsoleAppVSPreview\ConsoleAppVSPreview\Program.cs", line: 4, character: 3)] // refers to the call at (L2, C2)
    public static void InterceptorMethod2(this Class c, string param) => Console.WriteLine($"Interceptor2 :: Name = {c.Name}, param = {param}");
}

namespace System.Runtime.CompilerServices
{
    sealed class InterceptsLocationAttribute(string filePath, int line, int character) : Attribute { }
}