たくのろじぃのメモ部屋

プログラミング・数学・マイクラなどの内容を備忘録として残すブログ。

【C#】同期メソッドから非同期メソッドを呼び出す

今までに、CoreRCON ライブラリ を用いてマイクラ自動化、もといマイクラプログラミングを色々やってきました。ただ、このライブラリを使うにあたって非同期処理のコーディングが必要になるので、「プログラミングを始めたばかり」の方には難しいかもしれません。

そこで、この CoreRCON を初心者向けにしたライブラリを作ろうと考えました。非同期処理を書かなくても良いので、とっつきやすいと思います。必要になってくるのは「使用者目線からは非同期であることを意識させない」ことです。

ただ正直、自分も非同期処理については完全に理解できていません。GitHub徘徊しながら写経したりして動作が分かってきたレベルなのでなんとも言えません...。

CoreRCON を使うときの話

非同期でない場合、正しく動作しません。

f:id:takunology:20201224131900p:plain

なので、async Task / await を付ける必要があります。

f:id:takunology:20201224133046p:plain

非同期を意識させない書き方

同期処理の中で非同期処理を動かしたいので、カプセル化していきます。

using System;
using System.Net;
using System.Threading.Tasks;
using CoreRCON;

class Program //利用者側の見える範囲
{
    static void Main(string[] args)
    {
        Minecraft minecraft = new Minecraft("127.0.0.1", 25575, "minecraft");
        string result = minecraft.SendCommand("/time set 0");
        Console.WriteLine(result);
    }
}

class Minecraft //開発者側の見える範囲
{
    private RCON rcon;

    public Minecraft(string ipaddress, ushort port, string password)
    {
        rcon = new RCON(IPAddress.Parse(ipaddress), port, password);
    }

    public string SendCommand(string Command)
    {
        return Task.Run(async () => {
            return await AsyncSendCommand(Command);
        }).GetAwaiter().GetResult();
    }

    private async Task<string> AsyncSendCommand(string str)
    {
        await rcon.ConnectAsync();
        return await rcon.SendCommandAsync(str);
    }
}

さて、全体をざっくりと眺めると、「利用者側」と「開発者側」で分けることができます。

まず、利用者側の Program クラスですがこの中で必要なことは、インスタンス生成とそのメソッドの呼び出しだけです。非同期処理 async /await を書かなくても、CoreRCON を利用してマイクラにコマンドを投げることができます。

次に、開発者側の Minecraft クラスです。この中で RCON のインスタンスを生成して非同期処理を書いています。同期メソッドから非同期なメソッドを呼び出すときには Task.Run() を使い、この中で非同期メソッドを実行します。実行する非同期メソッドは別で宣言しており、コマンドを投げたときの結果が欲しいのでジェネリクスに文字列型を指定しています。これを同期メソッドから呼び出して、その返り値を Task.Run から返しています。最後に GetAwaiter()GetResult() を用いてタスクを待機し、それが完了したら待機を終了するみたいです。

ちょっと複雑なのですが、簡単な流れを書くと

AsyncSendCommand () : 非同期メソッド

⇧ Task.Run() で非同期メソッド呼び出し

SendCommand() : 同期メソッド

⇧ Main() からの呼び出し

Program クラス

となります。正直、面倒ですがライブラリとして使用する分には簡単になると思います。

参考サイト

参考になったサイトです。ありがとうございます。

nryblog.work

docs.microsoft.com

docs.microsoft.com

docs.microsoft.com