Orleans コード生成

Orleans 7.0 より前のソース生成は、はるかに手動部分が多く、開発者がはっきりと介入する必要がありました。 Orleans 7.0 以降のコード生成は自動的に行われ、開発者が介入する必要はありません。 ただし、それでも、開発者がコード生成に影響を与えたい場合はあります。たとえば、自動的に生成されない型のコードを生成する場合や、別のアセンブリの型用のコードを生成する場合です。

コード生成を有効にする

Orleans では、ビルド時にアプリ用の C# ソース コードが生成されます。 ホストを含むすべてのプロジェクトで、コード生成を有効にするには、適切な NuGet パッケージがインストールされている必要があります。 次のパッケージを使用できます。

型がシリアル化を意図されていること、およびその型に対するシリアル化コードを生成する必要があることを指定するには、GenerateSerializerAttribute を使います。 詳しくは、「Orleans のシリアル化を使用する」をご覧ください。

Orleans ランタイムでは生成されたコードを利用して、確実にクラスター全体で使用される型が適切にシリアル化され、定型が生成されるようにします。これにより、メソッドの配布、例外伝達、およびその他の内部ランタイムの概念の実装の詳細が抽象化されます。 コード生成は、プロジェクトのビルド時またはアプリケーションの初期化時に実行できます。

ビルド中の動作

ビルド時に、Orleans は GenerateSerializerAttribute でマークされているすべての型のコードを生成します。 GenerateSerializer でマークされていない型は、Orleans によってシリアル化されません。

F# または Visual Basic を使って開発している場合でも、コード生成を使用できます。 詳しくは、次のサンプルを参照してください。

これらの例では、Orleans.GenerateCodeForDeclaringAssemblyAttribute を使用し、ソース ジェネレーターで調べてソースを生成する必要があるアセンブリ内の型を指定する方法が示されています。

ビルド時にコード生成を行うことをお勧めします。 ビルド時のコード生成は、次のいずれかのパッケージを使用して有効にすることができます。

  • Microsoft.Orleans.OrleansCodeGenerator.Build。 コード生成に Roslyn を使用し、分析に .NET Reflection を使用するパッケージ。
  • Microsoft.Orleans.CodeGenerator.MSBuild。 コード生成とコード分析の両方に Roslyn を活用する新しいコード生成パッケージ。 アプリケーション バイナリは読み込まれません。その結果、競合する依存関係のバージョンと異なるターゲット フレームワークが原因で発生する問題が回避されます。 新しいコード ジェネレーターでは、インクリメンタル ビルドのサポートも改善されます。これにより、ビルド時間が短縮されるはずです。

これらのパッケージの 1 つは、グレイン、グレイン インターフェイス、カスタム シリアライザー、またはグレイン間で送信される型を含むすべてのプロジェクトにインストールする必要があります。 パッケージをインストールすると、ビルド時にコードを生成するターゲットがプロジェクトに挿入されます。

両方のパッケージ (Microsoft.Orleans.CodeGenerator.MSBuildMicrosoft.Orleans.OrleansCodeGenerator.Build) でサポートされるのは C# プロジェクトのみです。 他の言語は、以下で説明する Microsoft.Orleans.OrleansCodeGenerator パッケージを使用するか、他の言語で記述されたアセンブリから生成されたコードのターゲットとして機能できる C# プロジェクトを作成することによってサポートされます。

追加の診断は、ターゲット プロジェクトの .csproj ファイルで OrleansCodeGenLogLevel の値を指定することで、ビルド時に出力できます。 たとえば、<OrleansCodeGenLogLevel>Trace</OrleansCodeGenLogLevel> のようにします。

初期化中の動作

Orleans 7 以降では、初期化中は何も行われません。 コード生成はビルド時に実行されます。

コード生成は、Microsoft.Orleans.OrleansCodeGenerator パッケージをインストールし、ApplicationPartManagerCodeGenExtensions.WithCodeGeneration 拡張メソッドを使用して、クライアントとサイロで初期化中に実行できます。

builder.ConfigureApplicationParts(
    parts => parts
        .AddApplicationPart(typeof(IRuntimeCodeGenGrain).Assembly)
        .WithCodeGeneration());

前述の例では、builder は、ISiloHostBuilder または IClientBuilder のいずれかのインスタンスにすることができます。 省略可能な ILoggerFactory インスタンスを WithCodeGeneration に渡して、コード生成中にログを有効にすることができます。以下に例を示します。

ILoggerFactory codeGenLoggerFactory = new LoggerFactory();
codeGenLoggerFactory.AddProvider(new ConsoleLoggerProvider());
    builder.ConfigureApplicationParts(
        parts => parts
            .AddApplicationPart(typeof(IRuntimeCodeGenGrain).Assembly)
            .WithCodeGeneration(codeGenLoggerFactory));

コード生成に影響を与える

GenerateSerializerAttribute を型に適用するときに、IdAttribute を適用してメンバーを一意に識別することもできます。 同様に、AliasAttribute で別名を適用することもできます。 コード生成に影響を与える方法について詳しくは、「Orleans のシリアル化を使用する」をご覧ください。

コード生成中に、特定の型のコード生成に影響を与えることができます。 グレイン インターフェイス、グレイン クラス、グレイン状態、およびグレイン メソッドで引数として渡される型に対してコードが自動的に生成されます。 型がこれらの基準に合わない場合は、次のメソッドを使用してコード生成をさらに指示できます。

型に SerializableAttribute を追加すると、その型のシリアライザーを生成するようにコード ジェネレーターに指示されます。

プロジェクトに [assembly: GenerateSerializer(Type)] を追加すると、その型をシリアル化可能として扱うようにコード ジェネレーターに指示されます。たとえば、型にアクセスできないために、その型に対してシリアライザーを生成できなかった場合にエラーが発生します。 コード生成が有効になっている場合、このエラーによってビルドが停止します。 この属性を使用すると、別のアセンブリから特定の型のコードを生成することもできます。

また、[assembly: KnownType(Type)] では、コード ジェネレーターに特定の型 (参照アセンブリからのものである可能性がある) を含めるよう指示されますが、その型にアクセスできない場合は例外は発生しません。

すべてのサブタイプのシリアライザーを生成する

インターフェイスまたはクラスに KnownBaseTypeAttribute を追加すると、その型を継承または実装するすべての型のシリアル化コードを生成するようにコード ジェネレーターに指示されます。

別のアセンブリ内のすべての型のコードを生成する

ビルド時に、生成されたコードを特定のアセンブリに含めることができない場合があります。 たとえば、Orleans を参照しない共有ライブラリ、C# 以外の言語で記述されたアセンブリ、および開発者がソース コードを持たないアセンブリが含まれる場合があります。 このような場合、これらのアセンブリの生成されたコードは、初期化中に参照される別のアセンブリに配置できます。

アセンブリに対してこれを有効にするには:

  1. C# プロジェクトを作成します。
  2. Microsoft.Orleans.CodeGenerator.MSBuild または Microsoft.Orleans.OrleansCodeGenerator.Build パッケージをインストールします。
  3. ターゲット アセンブリへの参照を追加します。
  4. C# ファイルの最上位レベルに [assembly: KnownAssembly("OtherAssembly")] を追加します。

KnownAssemblyAttribute では、指定されたアセンブリを検査し、その中に型のコードを生成するようにコード ジェネレーターに指示されます。 この属性は、プロジェクト内で複数回使用できます。

その後、生成されたアセンブリを初期化中にクライアントまたはサイロに追加する必要があります。

builder.ConfigureApplicationParts(
    parts => parts.AddApplicationPart("CodeGenAssembly"));

前述の例では、builder は、ISiloHostBuilder または IClientBuilder のいずれかのインスタンスにすることができます。

KnownAssemblyAttribute には省略可能なプロパティ TreatTypesAsSerializable があります。これを true に設定して、そのアセンブリ内のすべての型がシリアル化可能としてマークされているかのように動作するようにコード ジェネレーターに指示できます。