SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

【C#で知っておくべき新機能】最新バージョンを徹底解説!

C# 12の新機能を紹介──型エイリアスやインライン配列など、待望の新機能とは?

【C#で知っておくべき新機能】最新バージョンを徹底解説! 第5回

  • X ポスト
  • このエントリーをはてなブックマークに追加

C# 12のプレビューモードで利用可能、インターセプタ(Interceptors)とは?

 C# 12では、インターセプタによりコンパイル時に置き換え可能なメソッドを定義可能になりました。

 インターセプタとは、その名の通りあるメソッドを実行時に別メソッドへリダイレクトする機能です。この機能により、開発時にのみ特化版のメソッドを実行することが可能になります。このインターセプタは、C# 12のプレビューモードでのみ利用可能です。以降のリリースで仕様が変更、あるいは削除される可能性がある旨を、Microsoftはアナウンスしています。よって、本番環境では利用しないことが推奨されます。

 以降、簡単なコンソールアプリケーションを作りながら、インターセプタの機能を検証してみます。まず、コンソールアプリケーションを作成します。

% dotnet new console -o interceptors

 プロジェクト設定ファイルに、以下のリストのようにインターセプタを有効にする名前空間の設定を追加します。C# 12 PreviewではInterceptorsPreviewを有効にする<Features>要素が必要でしたが、リリース版では不要になっています。

interceptors/interceptors.csproj
<PropertyGroup>
  <OutputType>Exe</OutputType>
  <TargetFramework>net8.0</TargetFramework>
  <ImplicitUsings>enable</ImplicitUsings>
  <Nullable>enable</Nullable>
  <InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);CSharp</InterceptorsPreviewNamespaces>	(1)
</PropertyGroup>

 (1)の追加行において指定されているCSharpは、以降のリストでインターセプタのコードを記述する名前空間になります。

 次に、以下のリストのような、メソッド呼び出しを行うコードをProgram.csファイルに記述します。この時点で、動作に問題のないことを確認しておきます。

interceptors/Program.cs
Console.WriteLine("オリジナルのWriteLine呼び出し");	(1)
MyClass c = new() { Prop = "プロパティ" };
c.Method("メソッド引数");				(2)

class MyClass
{
    public string Prop { get; set; }
    public void Method(string param) => Console.WriteLine($"オリジナルのメソッド呼び出し: prop = '{Prop}', param = '{param}'");				(3)
}

 (1)(2)は置き換え対象のメソッド呼び出しですが、異なるのは(2)の方はクラスのプロパティも表示している点です。(3)のメソッド定義では、クラスのプロパティと引数の双方を表示する仕様になっています。

 この時点でプロジェクトをビルド、実行し、以下のように出力されることを確認してください。

オリジナルのWriteLine呼び出し
オリジナルのメソッド呼び出し: prop = 'プロパティ', param = 'メソッド引数'

 ここで、インターセプタを追加します。同じくProgram.csファイルに、インターセプタのコードを以下のリストのように追記します(filePath引数には、各自のソースファイルのパスを指定してください)。

interceptors/Program.cs
namespace CSharp {							(1)
    static class Interceptor {						(2)
        [System.Runtime.CompilerServices.InterceptsLocation(		(3)
            filePath: @"/Users/…/interceptors/Program.cs", 
            line: 4, 
            character: 9)]
        public static void InterceptWriteLine(string? message)		(4)
        {
            Console.WriteLine($"インターセプトされたWriteLine呼び出し: message = '{message}'");
        }

        [System.Runtime.CompilerServices.InterceptsLocation(		(3)
            filePath: @"/Users/…/interceptors/Program.cs", 
            line: 6, 
            character: 3)]
        public static void InterceptorMethod(this MyClass c, string param) => Console.WriteLine($"インターセプトされたメソッドの呼び出し: prop = '{c.Prop}', param = '{param}'");							(5)
    }
}

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public sealed class InterceptsLocationAttribute(string filePath, int line, int character) : Attribute						(6)
    {
    }
}

 (1)では、interceptors.csprojファイルで指定した名前空間をここにも指定します。

 (2)は、インターセプタの静的メソッドを格納するための静的クラスの宣言です。名前は何でも構いません。

 (3)は、インターセプトするメソッド呼び出しの位置を正確に指定するための属性です。この属性は(6)にて定義されるクラスです。

 (4)(5)は、インターセプトで置き換える側のメソッド定義です。(4)は引数のみを処理すればいいので改めてWriteLineメソッドを呼び出す処理になっていますが、(5)はクラスのインスタンスも受け取る必要があるので、thisパラメータを第1引数に指定しています。これにより、静的メソッドでありながらインスタンスメソッドのインターセプトも可能になっています。

 改めて(6)ですが、これは(3)で指定している属性の定義に相当します。

 改めてビルド、実行してみると、インターセプトしたメソッドによって実行結果が変化していることが分かります。

インターセプトされたWriteLine呼び出し: message = 'オリジナルのWriteLine呼び出し'
インターセプトされたメソッドの呼び出し: prop = 'プロパティ', param = 'メソッド引数'

System.Runtime.CompilerServices名前空間

 上記(6)のInterceptsLocation属性は、System.Runtime.CompilerServices名前空間内で定義する必要がありますが、このような名前空間に独自の定義を追加することは、通常は行いません。公式ドキュメントにも明確な記述はありませんが、インターセプタは実験的な機能なので、このようなルールになっていると思われます。

まとめ

 今回は、任意の型エイリアス、インライン配列、Experimental属性、インターセプタについて紹介しました。

 C#では、本連載で紹介したように、より使い勝手を良くする改変が新バージョンで施されています。よりモダンで使い勝手のよい言語として成長し続けるC#を、今後も見守っていきたいものです。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
【C#で知っておくべき新機能】最新バージョンを徹底解説!連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook <個人紹介> WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/19164 2024/03/22 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング