【C#】拡張メソッド .ToString() 的なやつをつくってみた

C# で大変お世話になっている .ToString() みたいなメソッドってどうやって作っているのか疑問に思って、色々調べたら 拡張メソッド という機能らしいです。名前は初めて知りました。

ライブラリを作っているとメソッドが増えて「わざわざ1行使って呼び出すのも面倒だなぁ...」と思うことがあるので、この機能は凄く便利です。

作り方

今回作るのは、List で定義したアイテムの要素を Minecraft でよく使う NBT に変換する拡張メソッドです。ポイントになるのは

  • そのクラスとメソッドは static でなければならない
  • 引数には this 修飾子をつけて、対応したい型を定義する

です。このルールに従って書いていきます。

public static class SlotItemsNBT
{
    public static List<string> ToNBT(this List<SlotItem> SlotItemList)
    {
        List<string> SlotItemsNBT = new List<string>();
        foreach (var item in SlotItemList)
        {
            SlotItemsNBT.Add("{" + $"Slot:{item.ItemSlot}b,id:\"{item.ItemID}\",Count:{item.ItemCount}b" + "}");
        }
        return SlotItemsNBT;
    }
}

ちなみに、SlotItem クラスはこのようになっています。

public class SlotItem
{
    public int ItemSlot { get; set; }
    public string ItemID { get; set; }
    public int ItemCount { get; set; }
    public SlotItem(int ItemSlot, string ItemID, int ItemCount)
    {
        this.ItemSlot = ItemSlot;
        this.ItemID = ItemID;
        this.ItemCount = ItemCount;
    }
}

使い方 1

使う(呼び出す)ときは、this で指定した型の変数の最後にくっつけるだけです。.ToString() と同じ使い方ですね。

まずは List で定義しただけの状態と、NBTに変換した状態で比べてみます。

List<SlotItem> Items = new List<SlotItem>()
{
    new SlotItem(0, "minecraft:oak_planks", 10),
    new SlotItem(1, "minecraft:diamond", 10),
    new SlotItem(2, "minecraft:birch_planks", 10)
};

foreach (var item in Items)
{
    Console.WriteLine(item);
}
Console.WriteLine();
foreach (var item in Items.ToNBT())
{
    Console.WriteLine(item);
}

実行結果

0       minecraft:oak_planks    10
1       minecraft:diamond       10
2       minecraft:birch_planks  10

{Slot:0b,id:"minecraft:oak_planks",Count:10b}
{Slot:1b,id:"minecraft:diamond",Count:10b}
{Slot:2b,id:"minecraft:birch_planks",Count:10b}

使い方 2

今度は宣言した List に直接拡張メソッドを作用させます。このとき、注意しないといけないのは .ToNBT() の返り値は List<string> なので、これに合わせないといけません。この場合は型推論を使ったほうが便利です。

var Items = new List<SlotItem>()
{
    new SlotItem(0, "minecraft:oak_planks", 10),
    new SlotItem(0, "minecraft:diamond", 10),
    new SlotItem(0, "minecraft:birch_planks", 10)
}.ToNBT(); //ここにくっつける

foreach (var item in Items)
{
    Console.WriteLine(item);
}

実行結果

{Slot:0b,id:"minecraft:oak_planks",Count:10b}
{Slot:1b,id:"minecraft:diamond",Count:10b}
{Slot:2b,id:"minecraft:birch_planks",Count:10b}

拡張の拡張

.ToString().GetType() のように拡張メソッドの後にも拡張メソッドをくっつけることができます。これも、拡張メソッドAの返り値が拡張メソッドBの this 引数と一致していればこのようなことができます。これを メソッドチェーン と言うみたいですね。(これも初めて知りました。)

.ToNBT() で NBT に変換する前に、アイテム名を昇順に並べ替える拡張メソッドを作ります。.ToNBT() の引数は this Item<SlotItem> なので、並べ替えるメソッドの返り値も Item<SlotItem> でなければなりません。

public static class ItemsSort
{
    public static List<SlotItem> SortByID(this List<SlotItem> SlotItemList)
    {
        List<SlotItem> SortedItemList = new List<SlotItem>();
        SortedItemList = SlotItemList
                        .OrderBy(x => x.ItemID)
                        .ThenBy(x => x.ItemSlot)
                        .ThenBy(x => x.ItemCount)
                        .ToList();
        return SortedItemList;
    }
}

これで .SortByID() でソートした後、ToNBT() で NBT に変換できます。つまり、.SortByID().ToNBT() ができます。

使い方

List<SlotItem> Items = new List<SlotItem>()
{
    new SlotItem(0, "minecraft:oak_planks", 10),
    new SlotItem(0, "minecraft:diamond", 10),
    new SlotItem(0, "minecraft:birch_planks", 10)
}.SortByID().ToNBT();

foreach (var item in Items)
{
    Console.WriteLine(item);
}

実行結果

{Slot:2b,id:"minecraft:birch_planks",Count:10:b}
{Slot:1b,id:"minecraft:diamond",Count:10:b}
{Slot:0b,id:"minecraft:oak_planks",Count:10:b}

先ほどの結果と見比べてみると、アイテム名がアルファベット順になっていることが確認できます。

参考サイト

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

qiita.com