C#で三菱PLCと通信する方法（第4弾）デバイス書き込みコマンドの使い方

## はじめに
前回の記事では、デバイス読み出しコマンドの使い方を紹介しました。

> 🔗 [第3弾はこちら](https://qiita.com/YudaiKitamura/items/94e8bc11fd5c6147baac)

今回は、McpXが対応している**デバイス書き込み系コマンド**を中心に、サンプルコードと一緒に紹介します。

## 使用ライブラリ
- [McpX](https://yudaikitamura.github.io/McpX/)

## 対応しているデバイス書き込みコマンド一覧

|名称|説明|同期メソッド|非同期メソッド|
|-|-|-|-|
|単一書き込み|指定デバイスに単一値を書き込みます。|`Write<T>(Prefix prefix, string address, T value)`|`WriteAsync<T>(...)`|
|一括書き込み|連続したデバイスに配列で指定した値を一括書き込みします。|`BatchWrite<T>(Prefix prefix, string address, T[] values)`|`BatchWriteAsync<T>(...)`|
|ランダム書き込み|非連続アドレスにワード・ダブルワード単位で書き込みます。|`RandomWrite<T1, T2>((Prefix prefix, string address, T1 value)[] wordDevices, (Prefix prefix, string address, T2 value)[] doubleWordDevices)`|`RandomWriteAsync<T1, T2>(...)`|

## デバイスアドレスの指定方法
McpXでは、各コマンドでPLCのデバイスを指定する際に、`Prefix`（デバイス種別）と `Address`（アドレス）を組み合わせて指定します。

`Prefix` は列挙型（`enum`）として定義されており、例えば内部リレー（M）を指定する場合は `Prefix.M`、データレジスタ（D）の場合は `Prefix.D` のように指定します。

`Address` は文字列型で指定します。
10進数のアドレスを指定する場合は `"1234"` のように、16進数のアドレスを指定する場合は `"4D2"` のように記述します。

:::note
対応しているデバイスなどの詳細は、前回の記事を参照してください。
[デバイス種別（Prefix）一覧](https://qiita.com/YudaiKitamura/items/94e8bc11fd5c6147baac#%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E7%A8%AE%E5%88%A5prefix%E4%B8%80%E8%A6%A7)
:::

## 書き込む型の指定方法
McpXでは、ジェネリックを使用した実装をしており、書き込むデータの型は、各メソッドのジェネリック型引数 `T` に指定します。
例えば、単一書き込みの`Write<T>(...)`メソッドでshort型を指定する場合は、`Write<short>(...)`のように記述します。

:::note
対応している型などの詳細は、前回の記事を参照してください。
[対応している型一覧](https://qiita.com/YudaiKitamura/items/94e8bc11fd5c6147baac#%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E5%9E%8B%E4%B8%80%E8%A6%A7)
:::

## 単一書き込み
指定したデバイスに対して、値を1つだけ書き込みます。

### 同期メソッドの例
D0 にshort型の 1234 を書き込む場合
```csharp
mcpx.Write<short>(Prefix.D, "0", (short)1234);
```

### 非同期メソッドの例
D10 にint型の 1234 を書き込む場合
```csharp
mcpx.WriteAsync<int>(Prefix.D, "10", 1234);
```

## 一括書き込み
連続するデバイスに対して、複数の値を一括で書き込みます。
### 同期メソッドの例
D0 〜 D9 にshort型の値、10点を読み込む場合
```csharp
short[] shortValues = new short[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
mcpx.BatchWrite<short>(Prefix.D, "0", shortValues);
```
### 非同期メソッドの例
D0 〜 D19 にint型の値、10点を書き込む場合
```csharp
int[] intValues = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
await mcpx.BatchWrite<int>(Prefix.D, "0", intValues);
```

## ランダム書き込み
非連続アドレスに対して任意のデータを書き込みたい場合に使用します。
ワード（16bit）、ダブルワード（32bit）単位で指定できます。
### 同期メソッドの例
ワード単位で、D8000 にshort型の 32766、D8010 にshort型の 32767、
ダブルワード単位で、D8020 にint型の 2147483646、D8030 にint型の 2147483647 を書き込む場合
```csharp
mcpx.RandomWrite<short, int>(
    wordDevices: [ 
        (Prefix.D, "8000", 32766),
        (Prefix.D, "8010", 32767)
    ],
    doubleWordDevices: [
        (Prefix.D, "8020", 2147483646),
        (Prefix.D, "8030", 2147483647) 
    ]
);
```
### 非同期メソッドの例
ワード単位で、D8000 にshort型の 32766、D8010 にshort型の 32767、
ダブルワード単位で、D8020 にint型の 2147483646、D8030 にint型の 2147483647 を書き込む場合
```csharp
await mcpx.RandomWriteAsync<short, int>(
    wordDevices: [ 
        (Prefix.D, "8000", 32766),
        (Prefix.D, "8010", 32767)
    ],
    doubleWordDevices: [
        (Prefix.D, "8020", 2147483646),
        (Prefix.D, "8030", 2147483647) 
    ]
);
```
## 同期メソッドと非同期メソッドの選び方
McpXでは、すべての書き込み系コマンドに同期版と非同期版の両方が用意されています。
選択のポイントは、アプリケーションの構造と処理負荷です。

### 同期メソッドを使うケース
- コンソールアプリやバッチ処理など、一連の処理が順次完了すればよい場合
- 通信待ちによるUIブロックが問題にならない場合
- ロジックをシンプルに保ちたい場合（学習・デバッグ中など）

### 非同期メソッドを使うケース
- WPFやWinForms、ASP.NETなど、UIやWebサーバーで非同期処理が求められる環境
- 通信中にアプリの応答性を保ちたい場合
- 複数のPLC通信や長時間通信を並列処理したい場合

## まとめ
今回は、三菱PLCと通信するための McpXライブラリの書き込み系コマンドについて紹介しました。

- `Write`, `BatchWrite`, `RandomWrite` 各メソッドの使用方法
- 同期／非同期メソッドの選定基準と使い分け方

また、GitHubにサンプルプロジェクトを載せてます。

https://github.com/YudaiKitamura/McpX/tree/main/Example


## 参考リンク
- [McpX ドキュメント](https://yudaikitamura.github.io/McpX/)
- [McpX GitHubリポジトリ](https://github.com/YudaiKitamura/McpX)
- [McpX NuGet](https://www.nuget.org/packages/McpX/)

---
💡 気になった方はぜひ[GitHubのリポジトリ](https://github.com/YudaiKitamura/McpX)をチェックしてみてください。  
よければ ⭐スター もよろしくお願いします！