この投稿ではC#の分解の例として、Unityゲームエンジンの各種Vector型の分解を紹介します。
C#の分解は、C# 7.0から利用可能です。
事前知識
- 公式ドキュメントタプルとその他の型の分解
- ufcppさんの複合型の分解
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に対応している環境・設定かを確認してください。