Unityの各種Vector型を分解

この投稿ではC#の分解の例として、Unityゲームエンジンの各種Vector型の分解を紹介します。

C#の分解は、C# 7.0から利用可能です。


事前知識


ValueTupleの分解の例

C#におけるValueTupleの分解の例を次に示します。

public static void Main(string[] args)

{
IEnumerable<int> source = LoadSource();

// ValueTupleとしでなく、分解して受ける
var (minValue, maxValue) = FindMinAndMax(source);
// 中略
}

(int min, int max) FindMinAndMax(IEnumerable<int> source)
{
int min, max;
// 中略
// ここでsource中の最小値・最大値を探す。空なら例外を投げる
return (min, max);
}

さて、この分解ですが各種ValueTuple型でなくても、その型がDeconstructという名前のインスタンスメソッドか拡張メソッドを持っていれば使うことができます。

標準ライブラリでは、各種Tupleクラス、KeyValuePair<TKey, TValue>クラスなどでも(環境によっては)利用可能です。これについては、こちらの「DeconstructメソッドがKeyValuePairなどに追加されて、ValueTupleみたいに分解宣言できるようになる」を参照してください。


Unityの各種Vector構造体を分解

Unityゲームエンジンの各種Vector構造体を分解できるようにします。

次のようなVector3構造体の拡張関数Deconstructを用意します。

using UnityEngine;

namespace VectorExtensions
{
public static class Extensions
{
public static void Deconstruct(this Vector3 value, out float x, out float y, out float z)
{
x = value.x;
y = value.y;
z = value.z;
}
}

// 略
}

これを次のように利用すると、Vector3を分解することができます。

using UnityEngine;

using VectorExtensions;

public class Example : MonoBehaviour
{
void Start()
{
var (x, y, z) = transform.position;
Debug.LogFormat("{0}, {1}, {2}", x, y, z);
}
}

最初がxで、次がy、最後がzであることに注意してください。


分解の乱用は非推奨

なんでもかんでも分解できるように拡張関数を生やすことはオススメしません。分解の乱用は推奨しません。

「どの順序でどの要素が分解されるか、利用者がコード・リファレンスを読まなくても、(ほぼ)正しく伝わる型」

のみで、分解を提供すべきだと思っています。

Vector3型などはコンストラクタに

float x = 0.0F;

float y = 1.0F;
float z = 2.0F;

var position = new Vector3(x, y, z)

があり、大抵のUnity開発者ならば、「分解されるならば、x、y、zの順番で分解されるだろう」、という共通認識を持てると思います。


コード例

以下、各種Vector構造体のDeconstruct拡張関数群を示します。

using UnityEngine;

namespace VectorExtensions
{
public static class Extensions
{
public static void Deconstruct(this Vector2 value, out float x, out float y)
{
x = value.x;
y = value.y;
}

public static void Deconstruct(this Vector3 value, out float x, out float y, out float z)
{
x = value.x;
y = value.y;
z = value.z;
}

public static void Deconstruct(this Vector4 value, out float x, out float y, out float z, out float w)
{
x = value.x;
y = value.y;
z = value.z;
w = value.w;
}

public static void Deconstruct(this Vector2Int value, out int x, out int y)
{
x = value.x;
y = value.y;
}

public static void Deconstruct(this Vector3Int value, out int x, out int y, out int z)
{
x = value.x;
y = value.y;
z = value.z;
}
}
}


注意

お使いのUnity・環境がC# 7.0に対応している環境・設定かを確認してください。