代碼生成
Orleans運(yùn)行時(shí)利用生成的代碼以確??缂簩?duì)象類型適當(dāng)?shù)匦蛄谢⑶疑砂逊椒▊鬟f、異常傳播和其他內(nèi)部運(yùn)行時(shí)概念的實(shí)現(xiàn)細(xì)節(jié)抽象掉的輔助代碼。(翻譯:野牛bison)
啟用代碼生成
代碼生成有兩種方式:運(yùn)行時(shí)生成和構(gòu)建時(shí)生成。
構(gòu)建時(shí)生成
構(gòu)建時(shí)生成是Orleans的首選方式,可以使用以下的包進(jìn)行構(gòu)建時(shí)代碼生成:
- Microsoft.Orleans.OrleansCodeGenerator.Build. 使用.Net 反射分析,并使用 Roslyn 生成代碼.
- Microsoft.Orleans.CodeGenerator.MSBuild. 一個(gè)新的代碼生成庫(kù),它利用Roslyn進(jìn)行代碼生成和代碼分析。 它不會(huì)加載應(yīng)用程序二進(jìn)制文件,因此可以避免因依賴版本沖突和不同的目標(biāo)框架而導(dǎo)致的問題;并且改進(jìn)了對(duì)增量構(gòu)建的支持,可以縮短構(gòu)建時(shí)間。
這些包應(yīng)安裝到所有項(xiàng)目中,包括 Grain, IGrain, 自定義序列化器和在 Grain 間傳遞的類型庫(kù)。安裝包會(huì)將一個(gè) Target 注入到項(xiàng)目中,在構(gòu)建時(shí)將生成代碼。
在 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')" />
注意:以上兩個(gè)軟件包只支持C#項(xiàng)目, 可以使用下面Microsoft.Orleans.OrleansCodeGenerator包支持其他語(yǔ)言,或者通過(guò)創(chuàng)建C#項(xiàng)目來(lái)支持其他語(yǔ)言,該項(xiàng)目可以充當(dāng)從用其他語(yǔ)言編寫的程序集生成的代碼的目標(biāo)。
通過(guò)在目標(biāo)項(xiàng)目的csproj文件中指定OrleansCodeGenLogLevel的值,可以在構(gòu)建時(shí)收集額外的診斷信息。 例如,
<OrleansCodeGenLogLevel>Trace</OrleansCodeGenLogLevel>。
運(yùn)行時(shí)生成
通過(guò)安裝Microsoft.Orleans.OrleansCodeGenerator包并使用IApplicationPartManager.WithCodeGeneration擴(kuò)展方法,可以在Client 和 Silo 啟動(dòng)時(shí)執(zhí)行代碼生成。
builder.ConfigureApplicationParts(
parts => parts
.AddApplicationPart(typeof(IRuntimeCodeGenGrain).Assembly)
.WithCodeGeneration());
在上面的示例中,builder可以是ISiloHostBuilder或IClientBuilder的實(shí)例。 ILoggerFactory(可選)實(shí)例可以傳遞給WithCodeGeneration以在代碼生成期間啟用日志記錄,例如:
ILoggerFactory codeGenLoggerFactory = new LoggerFactory();
codeGenLoggerFactory.AddProvider(new ConsoleLoggerProvider());
builder.ConfigureApplicationParts(
parts => parts
.AddApplicationPart(typeof(IRuntimeCodeGenGrain).Assembly)
.WithCodeGeneration(codeGenLoggerFactory));
定制代碼生成
為特定類型生成代碼
代碼生成組件會(huì)自動(dòng)為 Grain的接口及其實(shí)現(xiàn)、Grain State和Grain方法的參數(shù)類型自動(dòng)生成代碼。如果要為額外的類型生成代碼,可以用下面的方法來(lái)使組件生成器為它們生成代碼:
- 將
[Serializable]添加到類型會(huì)指示代碼生成器為該類型生成序列化程序。 - 將
[assembly:GenerateSerializer(Type)]添加到項(xiàng)目會(huì)指示代碼生成器將該類型視為可序列化,如果無(wú)法為該類型生成序列化程序,則會(huì)導(dǎo)致錯(cuò)誤,例如因?yàn)樵擃愋筒豢稍L問。 如果啟用了代碼生成,則此錯(cuò)誤將暫停構(gòu)建。 此屬性還允許從另一個(gè)程序集生成特定類型的代碼。 -
[assembly:KnownType(Type)]還指示代碼生成器包含特定類型(可能來(lái)自引用的程序集),但如果類型不可訪問則不會(huì)導(dǎo)致異常。
為所有子類型生成代碼
將[KnownBaseType]添加到接口或類會(huì)指示代碼生成器為繼承/實(shí)現(xiàn)該類型的所有類型生成序列化代碼。
為另一個(gè)程序集中的所有類型生成代碼
在某些情況下,生成的代碼在構(gòu)建時(shí)不能包含在特定的程序集中。 例如,這可以包括不引用Orleans的共享庫(kù),用C#以外的語(yǔ)言編寫的程序集,以及開發(fā)人員沒有源代碼的程序集。 在這些情況下,可以將這些程序集的生成代碼放入一個(gè)在初始化期間引用的單獨(dú)程序集中。
為了做到這一點(diǎn),我們需要按如下步驟操作:
- 創(chuàng)建一個(gè) C# 項(xiàng)目
- 安裝
Microsoft.Orleans.CodeGenerator.MSBuild或Microsoft.Orleans.OrleansCodeGenerator.Build - 將目標(biāo)程序集添加到引用
- 在C#文件頂部添加
[assembly: KnownAssembly("OtherAssembly")]
KnownAssembly屬性指示代碼生成器檢查指定的程序集并為其中的類型生成代碼。 該屬性可以在項(xiàng)目中多次使用。
然后必須在初始化期間將生成的程序集添加到 Client / Silo中:
builder.ConfigureApplicationParts(
parts => parts.AddApplicationPart("CodeGenAssembly"));
在上面的示例中,builder可以是ISiloHostBuilder或IClientBuilder的實(shí)例。
KnownAssemblyAttribute有一個(gè)可選屬性TreatTypesAsSerializable,可以將其設(shè)置為true以指示代碼生成器視該程序集中的所有類型都為可序列化類型。