代碼生成
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)致的問(wèn)題瞧壮;并且改進(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ǔ)言編寫(xiě)的程序集生成的代碼的目標(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問(wèn)是钥。 如果啟用了代碼生成掠归,則此錯(cuò)誤將暫停構(gòu)建。 此屬性還允許從另一個(gè)程序集生成特定類型的代碼悄泥。 -
[assembly:KnownType(Type)]
還指示代碼生成器包含特定類型(可能來(lái)自引用的程序集)虏冻,但如果類型不可訪問(wèn)則不會(huì)導(dǎo)致異常。
為所有子類型生成代碼
將[KnownBaseType]
添加到接口或類會(huì)指示代碼生成器為繼承/實(shí)現(xiàn)該類型的所有類型生成序列化代碼弹囚。
為另一個(gè)程序集中的所有類型生成代碼
在某些情況下厨相,生成的代碼在構(gòu)建時(shí)不能包含在特定的程序集中。 例如鸥鹉,這可以包括不引用Orleans的共享庫(kù)蛮穿,用C#以外的語(yǔ)言編寫(xiě)的程序集,以及開(kāi)發(fā)人員沒(méi)有源代碼的程序集毁渗。 在這些情況下践磅,可以將這些程序集的生成代碼放入一個(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
以指示代碼生成器視該程序集中的所有類型都為可序列化類型么伯。