2.2 Orleans 中的代码生成

<<返回目录

代码生成

Orleans运行时利用生成的代码以确保跨集群对象类型适当地序列化,并且生成把方法传递、异常传播和其他内部运行时概念的实现细节抽象掉的辅助代码。(翻译:野牛bison)

启用代码生成

代码生成有两种方式:运行时生成和构建时生成。

构建时生成

构建时生成是Orleans的首选方式,可以使用以下的包进行构建时代码生成:

  • Microsoft.Orleans.OrleansCodeGenerator.Build. 使用.Net 反射分析,并使用 Roslyn 生成代码.
  • Microsoft.Orleans.CodeGenerator.MSBuild. 一个新的代码生成库,它利用Roslyn进行代码生成和代码分析。 它不会加载应用程序二进制文件,因此可以避免因依赖版本冲突和不同的目标框架而导致的问题;并且改进了对增量构建的支持,可以缩短构建时间。

这些包应安装到所有项目中,包括 Grain, IGrain, 自定义序列化器和在 Grain 间传递的类型库。安装包会将一个 Target 注入到项目中,在构建时将生成代码。

在 dotnet core中, target配置在xxx.csproj.nuget.g.targets中,例如:

    <Import Project="$(NuGetPackageRoot)microsoft.orleans.codegenerator.msbuild\2.3.2\build\Microsoft.Orleans.CodeGenerator.MSBuild.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.orleans.codegenerator.msbuild\2.3.2\build\Microsoft.Orleans.CodeGenerator.MSBuild.targets')" />

注意:以上两个软件包只支持C#项目, 可以使用下面Microsoft.Orleans.OrleansCodeGenerator包支持其他语言,或者通过创建C#项目来支持其他语言,该项目可以充当从用其他语言编写的程序集生成的代码的目标。

通过在目标项目的csproj文件中指定OrleansCodeGenLogLevel的值,可以在构建时收集额外的诊断信息。 例如,

<OrleansCodeGenLogLevel>Trace</OrleansCodeGenLogLevel>。

运行时生成

通过安装Microsoft.Orleans.OrleansCodeGenerator包并使用IApplicationPartManager.WithCodeGeneration扩展方法,可以在Client 和 Silo 启动时执行代码生成。

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

在上面的示例中,builder可以是ISiloHostBuilderIClientBuilder的实例。 ILoggerFactory(可选)实例可以传递给WithCodeGeneration以在代码生成期间启用日志记录,例如:

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

定制代码生成

为特定类型生成代码

代码生成组件会自动为 Grain的接口及其实现、Grain State和Grain方法的参数类型自动生成代码。如果要为额外的类型生成代码,可以用下面的方法来使组件生成器为它们生成代码:

  • [Serializable]添加到类型会指示代码生成器为该类型生成序列化程序。
  • [assembly:GenerateSerializer(Type)]添加到项目会指示代码生成器将该类型视为可序列化,如果无法为该类型生成序列化程序,则会导致错误,例如因为该类型不可访问。 如果启用了代码生成,则此错误将暂停构建。 此属性还允许从另一个程序集生成特定类型的代码。
  • [assembly:KnownType(Type)]还指示代码生成器包含特定类型(可能来自引用的程序集),但如果类型不可访问则不会导致异常。

为所有子类型生成代码

[KnownBaseType]添加到接口或类会指示代码生成器为继承/实现该类型的所有类型生成序列化代码。

为另一个程序集中的所有类型生成代码

在某些情况下,生成的代码在构建时不能包含在特定的程序集中。 例如,这可以包括不引用Orleans的共享库,用C#以外的语言编写的程序集,以及开发人员没有源代码的程序集。 在这些情况下,可以将这些程序集的生成代码放入一个在初始化期间引用的单独程序集中。

为了做到这一点,我们需要按如下步骤操作:

  • 创建一个 C# 项目
  • 安装Microsoft.Orleans.CodeGenerator.MSBuildMicrosoft.Orleans.OrleansCodeGenerator.Build
  • 将目标程序集添加到引用
  • 在C#文件顶部添加[assembly: KnownAssembly("OtherAssembly")]

KnownAssembly属性指示代码生成器检查指定的程序集并为其中的类型生成代码。 该属性可以在项目中多次使用。

然后必须在初始化期间将生成的程序集添加到 Client / Silo中:

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

在上面的示例中,builder可以是ISiloHostBuilderIClientBuilder的实例。

KnownAssemblyAttribute有一个可选属性TreatTypesAsSerializable,可以将其设置为true以指示代码生成器视该程序集中的所有类型都为可序列化类型。