3rd term 2nd week - dsuz/csharp GitHub Wiki

今回のテーマ

  • 拡張メソッド

  • ユーザー定義型(自分で作ったクラスや構造体)に機能を追加する

    • IComparable インターフェイスを継承して比較可能にする
    • 演算子をオーバーロードして新たな演算を定義する
    • ToString() をオーバーライドしてログ出力などをしやすくする

準備

以下のアセットを Unity プロジェクトにインポートします

拡張メソッド

既存のクラスに自分で作ったメソッドを追加することができる。この時、追加したメソッドを「拡張メソッド」と呼ぶ。拡張メソッドは以下のように書いて追加することができる。

static class '適当なクラス名'
{
    public static '戻り値の型' 'メソッド名'(this '拡張したいクラスの名前' '引数の変数名', 'メソッドの引数の型1' 'メソッドの引数の変数名1', ...)
    {
        // 拡張メソッドの処理をここに書く
    }
}

以下は、Vector3 クラスに、指定した座標との距離を求めるインスタンスメソッド Distance() (※2)を拡張メソッドとして追加するコードである。

using UnityEngine;

/// <summary>
/// 拡張メソッドを定義する
/// </summary>
static class Vector3Extensions
{
    /// <summary>
    /// インスタンスを起点座標とし、destination を終点座標として起点から終点までの距離を求める
    /// </summary>
    /// <param name="origin">起点座標</param>
    /// <param name="destination">終点座標</param>
    /// <returns></returns>
    public static float Distance(this Vector3 origin, Vector3 destination)
    {
        return Vector3.Distance(origin, destination);
    }
}

(※2)Vector3 クラスには、2点間の距離を求める static メソッド Distance() は既にある。

実際は拡張メソッドは既に使っている。例えば、Linq は既存のクラスに追加された拡張メソッドである。DOTween は Transform, Rigidbody, Camera, Light, Material 等に拡張メソッドを追加している。

ユーザー定義型

自分で作った型をユーザー定義型 (user-defined types, UDT) と言います。カスタム クラスとか自作クラスとも言います。ただし、構造体も型ですから、ユーザー定義型というのが正確です。

Unity 上で C# でコンポーネントを作った時、コンポーネントはクラスですから、コンポーネントはユーザー定義型です。

もちろん Unity 上でも、MonoBehaviour を継承せずにユーザー定義型を作って、データを扱うための型を定義することができます。

ユーザー定義型を作った時、今回学ぶことをしておかないといろいろと不便な事があります。例えば、Vector3 は Unity によって定義されている構造体ですが、Vector3 と Vector3 は足すことができます。しかし、Vector3 と Vector3 は比較することができません。なぜならそれは定義されていないからです。また、Vector3.ToString() を呼ぶと、戻り値として (x, y, z) の形式で x 要素, y 要素, z 要素を文字列で受け取れます。これによりログ出力した時に見やすくなります。

このように、自分で作ったユーザー定義型にも 比較・演算・文字列への変換を定義しておくことでデータの操作等が簡単にできるようになります。

IComparable インターフェイス

IComparable インターフェイスを継承して CompareTo メソッドを実装することにより、そのクラスのインスタンスはソート可能になる。CompareTo メソッドは object 型を引数にとり、int 型の値を返す。

引数として受け取る object 型の値は、現在のインスタンスと比較するインスタンスであり、戻り値としては、以下の要領で「負の値」「0」「「正の値」を返す。

  1. 現在のインスタンスを比較対象のインスタンスより昇順ソートの順番で前としたい時、負の値を返す
  2. 現在のインスタンスを比較対象のインスタンスより昇順ソートの順番で後ろとしたい時、正の値を返す
  3. 現在のインスタンスと比較対象のインスタンスを昇順ソートの順番で同じ、としたい時、0 を返す

今回のサンプルでそれを実装しているのは MyCustomClass.CompareTo() です。これにより、ボタンをクリックして DataLoader.SortGearData() を呼び出した時に Sort() メソッドで簡単にソートすることができるようになります。このサンプルでは Gear クラスを ID 順でソートするように定義してあります。

演算子のオーバーロード

ユーザー定義型に対して演算を定義したいことがある。そのような時、オーバーロード可能な演算子 に挙げられている演算子はオーバーロードして自分で演算を定義することができる。

今回のサンプルでは MyCustomClass で Gear 同士の足し算を定義しています。Gear はアイテム(装備)のデータですが、足し算によりアイテムを「合成」し、和として新たなアイテムが得られるようにしています。得られるアイテムはランダムです。ボタンをクリックして InventoryTest.Fusion() を呼び出した時にアイテムを合成しています。

条件式等でユーザー定義型のインスタンス同士を比較したい時は、等号・不等号をオーバーロードしてやればよいです。

ToString() のオーバーライド

ToString() メソッドの一般的な役割は、「インスタンスの文字列表現を返す」である。UnityEngine.Vector3 や UnityEngine.Color, System.DateTime などがわかりやすい。

ユーザー定義型でも、そのクラスのインスタンスに格納されているデータの文字列による表現を簡単にわかりやすく取り出したいケースは頻繁にある。そのような場合は、適宜 ToString() メソッドをオーバーライドし、適切な文字列表現を返す処理を追加する。

参考資料

  • 拡張メソッド

    • 独習 C# 8.2.9 拡張メソッド
  • 演算子のオーバーロード

    • 独習 C# 9.7 - 演算子のオーバーロード
  • ToString() メソッドのオーバーライド

    • 独習 C# 9.6.2 - オブジェクトの文字列表現を取得する ― ToString メソッド
⚠️ **GitHub.com Fallback** ⚠️