コンテンツにスキップ

インタフェース

書き方説明
interface IShape { float Area(); }インタフェースの宣言と実装
interface IValue { int Id { get; } }インタフェースのプロパティ
public int Id { get { return 1; } }計算して返すプロパティの実装
interface IFast : IGadgetインタフェースどうしの継承
struct Box : IShape値型による実装
record Tag(int N) : ILabelrecord による実装
class C : TsukimiBehaviour, IGadgetBehaviour による実装
struct Both : IGadget, IReset値型による複数の実装
class C : TsukimiBehaviour, IGadget, IResetBehaviour による複数の実装
IShape s = new Box();ローカル変数での保持
void Use(IShape s)引数での受け取り
IShape Make()戻り値での返却
IShape[] all = new IShape[2];インタフェースの配列への値型の格納
public IGadget other;インタフェース型のフィールドでの保持
other is IReset別のインタフェースへの型テスト
public IGadget[] all;インタフェース型の配列での保持
GetComponent<IGadget>()インタフェースを指定した取得
other != nullnull との比較
other?.Tick()null 条件の呼び出し
s is Box具象の型の判定
s switch { Box b => ..., _ => ... }具象の型による分岐
s switch { Box b => ..., Dot d => ... }既定のケースを置かない分岐
where T : IShapeインタフェースによる型引数の制約
書き方説明エラー理由代わりに
int IValue.Id { get { return 1; } }(実装する側)インタフェースのプロパティを明示的に実装するTUKI0001設計public のプロパティとして実装する
v.Id(v は Behaviour に付けたインタフェース)Behaviour に付けたインタフェースのプロパティを読むTUKI0001設計インタフェース側をメソッド(int Id();)にする(値型の実装ならプロパティのまま読める)
int Twice() { return Value() * 2; }インタフェースに既定の実装を書くTUKI0001設計実装する側それぞれに書く
float IShape.Area() { ... }明示的に実装するTUKI0001設計普通の public メソッドとして実装する
private IShape held;値型に付けたインタフェースをフィールドに持つTUKI0001未実装ローカル変数・引数で受け渡す。Behaviour に付けたものならフィールドに持てる
Box b = (Box)s;インタフェースから具象へキャストするTUKI0001未実装型パターン(s switch { Box b => ... })で受ける
IGadget g = new Widget(); g is IReset値型を入れたインタフェースへの型テストTUKI0001未実装Behaviour に付けたインタフェースで受けるか、具象の型で見る
IShape s = new Box(); s == null値型に付けたインタフェースを null と比べるTUKI0001設計Behaviour に付けたインタフェースで受ける(値型の値は null にならない)
IShape s = new Box(); s?.Area()値型に付けたインタフェースに ?. を使うTUKI0001設計同上
値型に付けたインタフェースは、ローカル変数・引数・戻り値・配列に置けます。フィールドには置けません。
Behaviour に付けたインタフェースは、フィールドにも配列にも置けて、null と比べられます。

値型に付けたインタフェースの値は、union(直和型)と同じ形に変換されます。いま入って いるのがどの型かを表す番号 1 つと、型ごとの置き場を並べたものです。書けない形が union とそろって いるのはこのためです。Behaviour に付けたインタフェースはこの形ではなく、Behaviour そのものを指します。

インタフェースに置けるのは、メソッドとプロパティの宣言だけです。本体を書くと断られます(書けない形)。

using UnityEngine;
using Tsukimi;
public interface IShape
{
float Area();
}
public struct Box : IShape
{
public float Area() { return 1f; }
}
public class IfaceDeclare : TsukimiBehaviour
{
void Start()
{
IShape s = new Box();
Debug.Log(s.Area()); // => 1
}
}
using UnityEngine;
using Tsukimi;
public interface IValue
{
int Id { get; }
}
public struct Num : IValue
{
public int Id { get; set; }
}
public class IfProperty : TsukimiBehaviour
{
void Start()
{
IValue v = new Num { Id = 7 };
Debug.Log(v.Id); // => 7
}
}

計算して返すプロパティの実装

Section titled “計算して返すプロパティの実装”

値型の実装は、本体を書くプロパティでもかまいません。明示的な実装にすると書けません(書けない形)。

using UnityEngine;
using Tsukimi;
public interface IValue
{
int Id { get; }
}
public struct Num : IValue
{
public int Id { get { return 1; } }
}
public class R_props : TsukimiBehaviour
{
void Start()
{
IValue v = new Num();
Debug.Log(v.Id); // => 1
}
}
using UnityEngine;
using Tsukimi;
public interface IGadget
{
void Tick();
}
public interface IFast : IGadget
{
void Boost();
}
public struct Runner : IFast
{
public void Tick() { Debug.Log(1); } // => 1
public void Boost() { Debug.Log(2); } // => 2
}
public class IfaceInherit : TsukimiBehaviour
{
void Start()
{
IFast f = new Runner();
f.Tick();
f.Boost();
}
}
using UnityEngine;
using Tsukimi;
public interface IShape
{
float Area();
}
public struct Box : IShape
{
public float Area() { return 1f; }
}
public class IfaceStructImplements : TsukimiBehaviour
{
void Start()
{
Box b = new Box();
IShape s = b;
Debug.Log(s.Area()); // => 1
}
}
using UnityEngine;
using Tsukimi;
public interface ILabel
{
int Id();
}
public record Tag(int N) : ILabel
{
public int Id() { return N; }
}
public class IfaceRecordImplements : TsukimiBehaviour
{
void Start()
{
ILabel l = new Tag(1);
Debug.Log(l.Id()); // => 1
}
}

Behaviour もインタフェースを実装できます。this を、そのインタフェースの型の変数へ入れられます。

using UnityEngine;
using Tsukimi;
public interface IGadget
{
void Tick();
}
public class IfaceBehaviourImplements : TsukimiBehaviour, IGadget
{
public void Tick() { Debug.Log(1); }
void Start()
{
IGadget g = this;
g.Tick();
}
}
using UnityEngine;
using Tsukimi;
public interface IGadget
{
void Tick();
}
public interface IReset
{
void Reset();
}
public struct Both : IGadget, IReset
{
public void Tick() { Debug.Log(1); } // => 1
public void Reset() { Debug.Log(2); } // => 2
}
public class IfaceStructMultipleInterfaces : TsukimiBehaviour
{
void Start()
{
Both b = new Both();
IGadget g = b;
IReset r = b;
g.Tick();
r.Reset();
}
}

Behaviour でも、複数のインタフェースを実装できます。

using UnityEngine;
using Tsukimi;
public interface IGadget
{
void Tick();
}
public interface IReset
{
void Reset();
}
public class IfaceBehaviourMultipleInterfaces : TsukimiBehaviour, IGadget, IReset
{
public void Tick() { Debug.Log(1); } // => 1
public void Reset() { Debug.Log(2); } // => 2
void Start()
{
Tick();
Reset();
}
}
using UnityEngine;
using Tsukimi;
public interface IShape
{
float Area();
}
public struct Box : IShape
{
public float Area() { return 1f; }
}
public class IfaceLocalVariable : TsukimiBehaviour
{
void Start()
{
IShape s = new Box();
Debug.Log(s.Area()); // => 1
}
}
using UnityEngine;
using Tsukimi;
public interface IShape
{
float Area();
}
public struct Box : IShape
{
public float Area() { return 1f; }
}
public class IfaceParameter : TsukimiBehaviour
{
void Start()
{
Use(new Box());
}
private void Use(IShape s)
{
Debug.Log(s.Area()); // => 1
}
}
using UnityEngine;
using Tsukimi;
public interface IShape
{
float Area();
}
public struct Box : IShape
{
public float Area() { return 1f; }
}
public class IfaceReturnValue : TsukimiBehaviour
{
void Start()
{
IShape s = Make();
Debug.Log(s.Area()); // => 1
}
private IShape Make()
{
return new Box();
}
}

インタフェースの配列への値型の格納

Section titled “インタフェースの配列への値型の格納”
using UnityEngine;
using Tsukimi;
public interface IShape
{
float Area();
}
public struct Box : IShape
{
public float Area() { return 1f; }
}
public class IfaceArrayOfValues : TsukimiBehaviour
{
void Start()
{
IShape[] all = new IShape[2];
all[0] = new Box();
all[1] = new Box();
float total = 0f;
for (int i = 0; i < all.Length; i++)
{
total += all[i].Area();
}
Debug.Log(total); // => 2
}
}

インタフェース型のフィールドでの保持

Section titled “インタフェース型のフィールドでの保持”

Behaviour に付けたインタフェースは、フィールドに持てます。

using UnityEngine;
using Tsukimi;
public interface IGadget
{
void Tick();
}
public class IfaceBehaviourField : TsukimiBehaviour, IGadget
{
public IGadget other;
public void Tick() { }
void Start()
{
other.Tick();
}
}

別のインタフェースへの型テスト

Section titled “別のインタフェースへの型テスト”

Behaviour に付けたインタフェースなら、別のインタフェースを実装しているかを見られます。値型を入れたインタフェースでは書けません(書けない形)。

using UnityEngine;
using Tsukimi;
public interface IGadget
{
void Tick();
}
public interface IReset
{
void Reset();
}
public class R_isc : TsukimiBehaviour, IGadget
{
public IGadget other;
public void Tick() { }
void Start()
{
bool b = other is IReset;
Debug.Log(b);
}
}

インタフェース型の配列での保持

Section titled “インタフェース型の配列での保持”

編集画面から複数の Behaviour を差し込んで、1 つのループで回せます。

using UnityEngine;
using Tsukimi;
public interface IGadget
{
void Tick();
}
public class IfaceBehaviourArray : TsukimiBehaviour, IGadget
{
public IGadget[] all;
public void Tick() { }
void Start()
{
for (int i = 0; i < all.Length; i++)
{
all[i].Tick();
}
}
}

インタフェースを指定した取得

Section titled “インタフェースを指定した取得”

型引数にインタフェースを指定して、それを実装した Behaviour を取れます。

using UnityEngine;
using Tsukimi;
public interface IGadget
{
void Tick();
}
public class IfaceGetComponent : TsukimiBehaviour, IGadget
{
public void Tick() { }
void Start()
{
IGadget g = GetComponent<IGadget>();
if (g != null)
{
g.Tick();
}
}
}

Behaviour に付けたインタフェースに対してだけ使えます。

using UnityEngine;
using Tsukimi;
public interface IGadget
{
void Tick();
}
public class IfaceCompareNull : TsukimiBehaviour, IGadget
{
public IGadget other;
public void Tick() { }
void Start()
{
Debug.Log(other == null); // => true
if (other != null)
{
other.Tick();
}
}
}

?. も、Behaviour に付けたインタフェースに対してだけ使えます。

using UnityEngine;
using Tsukimi;
public interface IGadget
{
void Tick();
}
public class IfaceNullConditional : TsukimiBehaviour, IGadget
{
public IGadget other;
public void Tick() { }
void Start()
{
other?.Tick();
}
}

具象の型かどうかを判定します。別のインタフェースを実装しているかは見られません(書けない形)。

using UnityEngine;
using Tsukimi;
public interface IShape
{
float Area();
}
public struct Box : IShape
{
public float Area() { return 1f; }
}
public class IfaceIsConcrete : TsukimiBehaviour
{
void Start()
{
IShape s = new Box();
bool isBox = s is Box;
Debug.Log(isBox); // => true
}
}
using UnityEngine;
using Tsukimi;
public interface IShape
{
float Area();
}
public struct Box : IShape
{
public float Area() { return 1f; }
}
public struct Dot : IShape
{
public float Area() { return 0f; }
}
public class IfaceSwitchTypePattern : TsukimiBehaviour
{
void Start()
{
IShape s = new Box();
float a = s switch
{
Box b => b.Area(),
Dot d => d.Area(),
_ => 0f,
};
Debug.Log(a); // => 1
}
}

実装した型のケースを尽くしていれば、既定のケースは要りません。union と同じです。

using UnityEngine;
using Tsukimi;
public interface IShape
{
float Area();
}
public struct Box : IShape
{
public float Area() { return 1f; }
}
public struct Dot : IShape
{
public float Area() { return 0f; }
}
public class IfaceSwitchExhaustive : TsukimiBehaviour
{
void Start()
{
IShape s = new Box();
float a = s switch
{
Box b => b.Area(),
Dot d => d.Area(),
};
Debug.Log(a); // => 1
}
}

インタフェースによる型引数の制約

Section titled “インタフェースによる型引数の制約”
using UnityEngine;
using Tsukimi;
public interface IShape
{
float Area();
}
public struct Box : IShape
{
public float Area() { return 1f; }
}
public class IfaceGenericConstraint : TsukimiBehaviour
{
void Start()
{
Debug.Log(Measure(new Box())); // => 1
}
private float Measure<T>(T shape) where T : IShape
{
return shape.Area();
}
}