C# Advent Calendar 2022 9日目の記事です。

MemoryPackとMAUIについて書いています。

[C#]MemoryPackを使ってみたい8 - MAUI(iOS/Android)のサンプル

dalian-spacekey/MemoryPackSampleApp

前回はTypeScriptのクライアントでMemoryPackのバイナリが読めるというのを確認しましたので、今回はMAUI(iOS/Android)でも大丈夫か確認します。

これは前回書いたとおり、過去に「サーバー + Webアプリ + iOS/Android」なシステムを作った経験を元に、そのデータのやりとりをJSONからMemoryPackに切り替えたら効率よくなるよね、というところから来ています。当時はXamarin.FormsでしたがさすがにもうMAUIが正式リリースされましたのでMAUIで動かしてみます。

今回はMAUI部分の解説をしますので、ベースとなるソリューションについては前回の記事を参照してください。

Mobileプロジェクト(src/Mobile)

Visual Studio 2022で生成した .NET MAUI アプリ からiOSとAndroid以外のプラットフォームを削除して作っています。

Xamarin.Forms時代はPrism.Formsを使っていましたが、Prism.Mauiもまだっぽいし、ちょっと動かすサンプルだと仰々しいのでCommunityToolkit.Mvvmを使ってみました。

APIサーバーとやりとりするクラスはSharedプロジェクトにある、ForCSharp がついたクラスになります。

HttpClient

Windows、Mac、それぞれのエミュレータを組み合わせてローカルで動作確認する場合、AndroidとiOSでlocalhostで動くAPIサーバーへのアクセスの仕方が違います。

ローカル コンピューターのアドレスを指定する

Androidの場合は10.0.2.2でいけると思いますが、iOSはWindowsをベースにしてmacをビルド/シミュレータな開発環境の場合にBaseAddressのIPアドレスを、macから通信できるものに変更する必要があります。

そこから派生して、JSON用とMemoryPack用のクライアントを作っていますが、今回はMemoryPackしか使っていません。JSONに入れ替えるのも簡単ですよと言うつもりで書いてあります。

Serialize/Deserialize

特に何か複雑な操作は必要なく、Acceptヘッダに application/x-memorypack を指定してHttpRequestが返してくるデータをDeserializeするだけです。JSONでやってることと何も変わらない。 こういったパターンでやりとりするデータだと処理の速さについては微々たるものですが、ペイロードのサイズは間違いなく小さくなりますし、フィールドが多かったりフィールド名が長い、とかだとさらに効率はよくなっていきます。

CommunityToolkit.Mvvmについて

コード生成を活用してめんどくさいコードを簡単な記述で実現してるのはすごくいいのです。が、なんかちょっと微妙にこっちが書きたいコードの感覚を外されるというか、生成されるコードがどんなものでどう動くのかがわかった上で使わないと書きづらい部分があります。

例えば、

[ObservableProperty] 
MessageForCSharp[] messages;

async Task LoadMessagesAsync()
{
    Messages = await messageModel.LoadAsync();
}

こういうObservablePropertyを宣言しておいて、それに値を入れてViewに通知を出すには、messagesではなく生成されているはずのMessagesプロパティに値を入れる必要がありますね。

これ普通にコードを書いている感覚だと、Messagesなんて見えてませんからさらっと書くのにちょっと抵抗があるのですね。 まあ何回かコード書いてみたらしょっちゅうバッキングフィールドの方に値を入れてしまって「表示されねぇ…」なんていうところにはまります。

そこに見えない生成されているものが頭に思い浮かんでないとコードが書きづらい…まあ要するに複数人で同じコードで作業をしていて、別の人が書いたコードを意識して書かないといけない感覚に似ています(というかそのもの)。

MemoryPackも当然コード生成バリバリ(というかだからこそ実現した)ライブラリなんですが、あくまでまとまった機能として生成されていて、コードを書く側は生成されたコードがどう書かれているか、なんて言うことは大して気にする必要がないのです。

他には、[ObservableProperty] に「On(プロパティ名)Changedメソッド」が生成されるとか、[RelayCommand] の場合に「(メソッド名)Command」が生成されるとか、こっちが直接触る部分が色々生成されているので、慣れるまでは隔靴掻痒の嘆ありです。

まとめ

これでMAUIとの間もMemoryPackが使えることがわかりました。前回のTypeScriptと併せて、過去に対応していたシステムでも使えそうです(もう手を離れているのでやりませんけど…)。

なぜもう今手を入れることもないシステムで使えるか確認したかったのかというと、かつてなんとか効率よいやりとりはできないかとか、技術的に単調になりがちな業務システムになにか新しいものを取り入れられないかと試行錯誤していて、当時同じくneueccさんが作っていたMessagePackを入れてやろうとか思ったんですが、色々複雑になりがちだったので諦めたのですね。

それが今回MemoryPackが出てきてよくよく見ると、なんか当時やりたかった「まるっと置き換えるだけでJSONを捨てられる、しかも最新鋭」が実現されていたのですね。中で行われていることは非常に高度で細かいことなので理解は全く追いつきませんが、それでも何も考えずに入れてしまっても安心して使えます。

GitHubのスターもどんどん増えているところを見ると多くの人が注目しています。これからいろんなところで使われるようになっていくんじゃないかなぁと思いますし、これがあるからサーバーをC#にしようかっていうケースも増えるといいなぁと思ってます。