※ これは 2023/10/05 時点の Unity 2023.1.16f1 の情報です
最新版では動作が異なる可能性がありますのでご注意ください
前回で Unity の Roslyn を利用したコード生成をやりやすくしたので、今度は MemoryPack 用の属性記述を自動生成してみたい
コード生成先のプロジェクトは下記のような手順で MemoryPack のパッケージ設定をしておく
スポンサードリンク
コード生成プロジェクトの CodeGenerator.cs
のコード出力部分
下記のところを
private void CreateProperties(GeneratorExecutionContext context, SyntaxReceiver receiver, Compilation compilation) { foreach (var classSyntax in receiver.TargetClasses) { var model = compilation.GetSemanticModel(classSyntax.SyntaxTree); var symbol = model.GetDeclaredSymbol(classSyntax); var name = symbol.Name; var properties = symbol.GetAttributes() .Where(x => x.AttributeClass.Name == "SimplePropertyAttribute") .Select(x => (Name: x.ConstructorArguments[0].Value.ToString(), Comment: x.ConstructorArguments[1].Value.ToString())) .ToArray(); var sb = new CodeBuilder(true); sb.AppendLine("using System.Collections.Generic;"); sb.AppendLine(); using (sb.BeginBlock($"public partial class {name}")) { foreach (var property in properties) { var publicName = char.ToUpper(property.Name[0]) + property.Name.Substring(1); var localName = char.ToLower(property.Name[0]) + property.Name.Substring(1); sb.AppendLine(); sb.AppendSummary(property.Comment); using (sb.BeginBlock($"public string {publicName}")) { sb.AppendLine($"get => this.{localName};"); using (sb.BeginBlock("set")) { using (sb.BeginBlock($"if (this.{localName} != value)")) { sb.AppendLine($"this.{localName} = value;"); } } } sb.AppendLine($"private string {localName} = null;"); } } context.AddSource($"{name}.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8)); } }
次のように変更
private void CreateProperties(GeneratorExecutionContext context, SyntaxReceiver receiver, Compilation compilation) { foreach (var classSyntax in receiver.TargetClasses) { var model = compilation.GetSemanticModel(classSyntax.SyntaxTree); var symbol = model.GetDeclaredSymbol(classSyntax); var name = symbol.Name; var properties = symbol.GetAttributes() .Where(x => x.AttributeClass.Name == "SimplePropertyAttribute") .Select(x => (Name: x.ConstructorArguments[0].Value.ToString(), Comment: x.ConstructorArguments[1].Value.ToString())) .ToArray(); var sb = new CodeBuilder(true); sb.AppendLine("using MemoryPack;"); sb.AppendLine("using System.Collections.Generic;"); sb.AppendLine(); sb.AppendLine("[MemoryPackable]"); using (sb.BeginBlock($"public partial class {name}")) { foreach (var property in properties) { var publicName = char.ToUpper(property.Name[0]) + property.Name.Substring(1); var localName = char.ToLower(property.Name[0]) + property.Name.Substring(1); sb.AppendLine(); sb.AppendSummary(property.Comment); sb.AppendLine("[MemoryPackIgnore]"); using (sb.BeginBlock($"public string {publicName}")) { sb.AppendLine($"get => this.{localName};"); using (sb.BeginBlock("set")) { using (sb.BeginBlock($"if (this.{localName} != value)")) { sb.AppendLine($"this.{localName} = value;"); } } } sb.AppendLine("[MemoryPackInclude]"); sb.AppendLine($"private string {localName} = null;"); } } context.AddSource($"{name}.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8)); } }
ところどころに MemoryPack 用の属性記述を挿入してみた
いつものように VSCode のソリューションエクスプローラーの右クリックメニューから「リビルド」実行
出力先プロジェクトを開いている UnityEditor に戻り、下記のような Data.cs
を追加
[Sample.SimpleProperty("Foo", "Fooプロパティ")] [Sample.SimpleProperty("Bar", "Barプロパティ")] public partial class Data { public Data() { } }
Test.cs は下記のように変更
using System.Collections; using System.Collections.Generic; using UnityEngine; public partial class Test : MonoBehaviour { // Start is called before the first frame update void Start() { var data = new Data() { Foo = "Foo", Bar = "Bar", }; var input = MemoryPack.MemoryPackSerializer.Serialize(data); var output = MemoryPack.MemoryPackSerializer.Deserialize<Data>(input); UnityEngine.Debug.Log($"---------------> {output.Foo}/{output.Bar}"); } }
[Ctrl] + [R] で再コンパイル
この Test.cs を Hierarchy 上の適当な GameObject にアタッチした上で実行すると⋯
エラー!⋯シリアライズに失敗した?!