コンテンツにスキップ

メンバの宣言

書き方説明注意
private int count;フィールド
private int count = 5;宣言と同時の代入
private const int Max = 10;定数
private static int Count;静的フィールド値は Behaviour のインスタンスごとに別で、インスタンスのあいだで共有されません。
private static readonly int Max = 10;静的な読み取り専用フィールド
private void Do()メソッドの宣言
private int Get()戻り値のあるメソッド
private int Add(int a, int b)引数のあるメソッド
int Add(int a, int b = 2)既定の引数
Add(b: 2, a: 1)名前つき引数
Add(int, int) / Add(float, float)オーバーロード
private int Twice(int n) => n * 2;式形式のメソッド
private static int Zero()静的メソッド
public int Value { get; set; }自動プロパティ
public int Doubled { get { return n * 2; } }計算するプロパティstruct の中では set を書けません(struct と record)。
{ get; private set; }取得と設定で異なる可視性
{ get; set; } = 1;プロパティの初期値
{ get; }取得だけの自動プロパティ
{ get; init; }init アクセサ
[field: SerializeField]バッキングフィールドへの属性
public virtual int V { get { … } }仮想プロパティ派生した型で上書きするには、基底の型を abstract にします。
public int this[int i]添字角括弧に書いた値は、アクセサの引数として渡されます。
this[0] = 3;添字への書き込みvalue に書き込む値が入り、添字は引数で受け取ります。
~C() { }ファイナライザ
private volatile int V;volatile
public readonly int Read()値型の readonly メンバ値型は渡すたびに複製されるので、付けても実行時の挙動は変わりません。
Add(1) / Add(1, 2)引数の数による選択
Show(1) / Show("a")引数の型による選択
Show(int) が Show(long) に勝つ変換の少ない候補の優先
Sum(1, 2)可変長引数への展開
Sum(int,int) が params に勝つ通常の候補の優先
Add(1)既定の引数の省略
Pick(1, 2)引数からの推論
First(new int[] { 1 })配列の要素からの推論
Left(1, "a")2 つの型引数の推論
Depth(new int[1][])入れ子の配列からの推論
true ? 1 : 2L?: の両側からの共通の型
public struct Inner { ... }入れ子の型
public partial class C分割して書く型
abstract int Get(); / override抽象メソッドの実装
virtual int Get() / override既定の実装の上書き基底の型は abstract でも具象でもかまいません。
base.Ring()基底の実装の呼び出し呼べるのは自分で書いた型の実装だけで、実行環境が定義するイベントの基底は呼べません。
書き方説明エラー理由代替
public class Base : TsukimiBehaviour ... public class Leaf : Base同じファイルに具象の型を 2 つ書くTUKI0109設計ファイルを分ける(具象の型の継承そのものは通ります)
public event System.Action Fired;event を宣言するTUKI0108環境メソッドを直接呼ぶか、名前を指定して送る
public event System.Action Fired { add { } remove { } }add/remove アクセサを自分で定義するTUKI0108環境同上
Fired?.Invoke()event で通知するTUKI0108環境メソッドを直接呼ぶか、名前を指定して送る
Fired += Handlerevent を購読するTUKI0108, TUKI0099環境同上
public static extern int Native()外部の実装を宣言するTUKI0001環境実行環境のメソッドを呼ぶ
Read(int v) と Read(in int v) を並べる渡し方の違いで候補を分けるTUKI0001未定名前を変える。in 単独は使える(変数と引数の渡し方)
public int Twice { get { … } set { … } }(struct の中)変更できる計算プロパティ(値型)TUKI0001未実装get だけにするか、メソッドにする(struct と record)
public int Extra { get; set; }(record の中)プロパティ(record)TUKI0001設計位置パラメータにするか、メソッドにする
c[0] = 1;(struct の中の添字)添字への書き込み(値型)TUKI0001未実装新しい値を返すメソッドにするか、Behaviour 側の添字を使う
panel[0](別の Behaviour の添字)別の Behaviour の添字を読むTUKI0001未定相手側にメソッドを置いて、それを呼ぶ
event宣言も書けません。宣言・購読・発火のどの行でも TUKI0108 です
~C() と volatileコンパイルも実行もでき、エラーも警告も出ませんが、書いても動作は変わりません
型そのものを初期化するメンバ静的コンストラクタもモジュール初期化子も TUKI0001 です(フィールドの初期化と既定値)

プロパティが対応するかどうかは、置く先とアクセサの 3 つの組み合わせで変わります。

置く先自動プロパティ計算する(get だけ)計算する(set あり)
Behaviour書ける書ける書ける
struct書ける書ける書けない
recordinit なら書ける書ける書けない
インタフェース書ける(実装する側も自動プロパティにする)書けない—
using UnityEngine;
using Tsukimi;
public class MemField : TsukimiBehaviour
{
private int count;
void Start()
{
Debug.Log(count); // => 0
}
}
using UnityEngine;
using Tsukimi;
public class MemFieldInitializer : TsukimiBehaviour
{
private int count = 5;
void Start()
{
Debug.Log(count); // => 5
}
}
using UnityEngine;
using Tsukimi;
public class MemConst : TsukimiBehaviour
{
private const int Max = 10;
void Start()
{
Debug.Log(Max); // => 10
}
}

インスタンスを作らずに読み書きします。

using UnityEngine;
using Tsukimi;
public class MemStaticField : TsukimiBehaviour
{
private static int Count;
void Start()
{
Count = 1;
Debug.Log(Count); // => 1
}
}

静的な読み取り専用フィールド

Section titled “静的な読み取り専用フィールド”

インスタンスを作らずに読み、あとから変更できません。

using UnityEngine;
using Tsukimi;
public class MemStaticReadonly : TsukimiBehaviour
{
private static readonly int Max = 10;
void Start()
{
Debug.Log(Max); // => 10
}
}
using UnityEngine;
using Tsukimi;
public class MemMethod : TsukimiBehaviour
{
private void Do() { Debug.Log(1); } // => 1
void Start()
{
Do();
}
}
using UnityEngine;
using Tsukimi;
public class MemMethodReturn : TsukimiBehaviour
{
private int Get() { return 1; }
void Start()
{
Debug.Log(Get()); // => 1
}
}
using UnityEngine;
using Tsukimi;
public class MemMethodParameters : TsukimiBehaviour
{
private int Add(int a, int b) { return a + b; }
void Start()
{
Debug.Log(Add(1, 2)); // => 3
}
}
using UnityEngine;
using Tsukimi;
public class MemDefaultArgument : TsukimiBehaviour
{
private int Add(int a, int b = 2) { return a + b; }
void Start()
{
Debug.Log(Add(1)); // => 3
}
}
using UnityEngine;
using Tsukimi;
public class MemNamedArgument : TsukimiBehaviour
{
private int Add(int a, int b) { return a + b; }
void Start()
{
Debug.Log(Add(b: 2, a: 1)); // => 3
}
}
using UnityEngine;
using Tsukimi;
public class MemOverload : TsukimiBehaviour
{
private int Add(int a, int b) { return a + b; }
private float Add(float a, float b) { return a + b; }
void Start()
{
Debug.Log(Add(1, 2) + Add(1f, 2f)); // => 6
}
}
using UnityEngine;
using Tsukimi;
public class MemExpressionBodied : TsukimiBehaviour
{
private int Twice(int n) => n * 2;
void Start()
{
Debug.Log(Twice(2)); // => 4
}
}
using UnityEngine;
using Tsukimi;
public class MemStaticMethod : TsukimiBehaviour
{
private static int Zero() { return 0; }
void Start()
{
Debug.Log(Zero()); // => 0
}
}
using UnityEngine;
using Tsukimi;
public class MemAutoProperty : TsukimiBehaviour
{
public int Value { get; set; }
void Start()
{
Value = 1;
Debug.Log(Value); // => 1
}
}

get の本体を自分で書くプロパティです。

using UnityEngine;
using Tsukimi;
public class MemComputedProperty : TsukimiBehaviour
{
private int n;
public int Doubled { get { return n * 2; } }
void Start()
{
n = 3;
Debug.Log(Doubled); // => 6
}
}
using UnityEngine;
using Tsukimi;
public class MbAccessorAcc : TsukimiBehaviour
{
void Start()
{
V = 1;
Debug.Log(V); // => 1
}
public int V { get; private set; }
}
using UnityEngine;
using Tsukimi;
public class MbAutoPropInit : TsukimiBehaviour
{
void Start()
{
Debug.Log(V); // => 1
}
public int V { get; set; } = 1;
}
using UnityEngine;
using Tsukimi;
public class MbGetterOnly : TsukimiBehaviour
{
void Start()
{
Debug.Log(V); // => 0
}
public int V { get; }
}
using UnityEngine;
using Tsukimi;
public class MbInitAccessor : TsukimiBehaviour
{
void Start()
{
Debug.Log(V); // => 0
}
public int V { get; init; }
}

バッキングフィールドへの属性

Section titled “バッキングフィールドへの属性”
using UnityEngine;
using Tsukimi;
public class MbFieldAttr : TsukimiBehaviour
{
void Start()
{
Debug.Log(V); // => 0
}
[field: SerializeField]
public int V { get; set; }
}

virtual を付けたプロパティです。

using UnityEngine;
using Tsukimi;
public class MbVirtualProp : TsukimiBehaviour
{
void Start()
{
Debug.Log(V); // => 1
}
public virtual int V { get { return 1; } }
}

this[int i] を宣言すると、その型の値を v[i] と書いて読めます。

using UnityEngine;
using Tsukimi;
public class MbIndexer : TsukimiBehaviour
{
void Start()
{
Debug.Log(this[2]); // => 20
}
public int this[int i] { get { return i * 10; } }
}

set も書くと v[i] = x と書いて書き込めます。

using UnityEngine;
using Tsukimi;
public class MbIndexerSet : TsukimiBehaviour
{
private int a;
private int b;
void Start()
{
this[0] = 3;
this[1] = 4;
Debug.Log(this[0] * 10 + this[1]); // => 34
}
public int this[int i]
{
get { return i == 0 ? a : b; }
set { if (i == 0) { a = value; } else { b = value; } }
}
}

対応しているが効果の無い構文

Section titled “対応しているが効果の無い構文”

ファイナライザを呼ぶ仕組みが実行環境に無いので、本体は一度も実行されません。

using UnityEngine;
using Tsukimi;
public class MbFinalizer : TsukimiBehaviour
{
void Start()
{
Debug.Log(1); // => 1
}
~MbFinalizer() { }
}

同時に実行される流れが無いので、volatile を付けても読み書きの意味は変わりません。

using UnityEngine;
using Tsukimi;
public class MbVolatile : TsukimiBehaviour
{
void Start()
{
Debug.Log(V); // => 0
}
private volatile int V;
}

値を変更しないメンバに付けられます。

using UnityEngine;
using Tsukimi;
public struct Point { public int X;
public readonly int Read() { return X; } }
public class MbReadonlyMember : TsukimiBehaviour
{
void Start()
{
Point p = new Point();
Debug.Log(p.Read()); // => 0
}
}
using UnityEngine;
using Tsukimi;
public class OvByArity : TsukimiBehaviour
{
void Start()
{
Debug.Log(Add(1)); // => 1
Debug.Log(Add(1, 2)); // => 3
}
private int Add(int a) { return a; }
private int Add(int a, int b) { return a + b; }
}
using UnityEngine;
using Tsukimi;
public class OvByType : TsukimiBehaviour
{
void Start()
{
Debug.Log(Show(1)); // => 1
Debug.Log(Show("a")); // => 2
}
private int Show(int a) { return 1; }
private int Show(string a) { return 2; }
}
using UnityEngine;
using Tsukimi;
public class OvBetterConv : TsukimiBehaviour
{
void Start()
{
Debug.Log(Show(1)); // => 2
}
private int Show(long a) { return 1; }
private int Show(int a) { return 2; }
}
using UnityEngine;
using Tsukimi;
public class OvExpanded : TsukimiBehaviour
{
void Start()
{
Debug.Log(Sum(1, 2)); // => 2
Debug.Log(Sum(new int[] { 1, 2 })); // => 2
}
private int Sum(params int[] xs) { return xs.Length; }
}
using UnityEngine;
using Tsukimi;
public class OvNormalBeatsParams : TsukimiBehaviour
{
void Start()
{
Debug.Log(Sum(1, 2)); // => 1
}
private int Sum(int a, int b) { return 1; }
private int Sum(params int[] xs) { return 2; }
}
using UnityEngine;
using Tsukimi;
public class OvDefaultArg : TsukimiBehaviour
{
void Start()
{
Debug.Log(Add(1)); // => 3
Debug.Log(Add(1, 5)); // => 6
}
private int Add(int a, int b = 2) { return a + b; }
}
using UnityEngine;
using Tsukimi;
public class OvInferArgs : TsukimiBehaviour
{
void Start()
{
Debug.Log(Pick(1, 2)); // => 1
}
private T Pick<T>(T a, T b) { return a; }
}
using UnityEngine;
using Tsukimi;
public class OvInferLower : TsukimiBehaviour
{
void Start()
{
Debug.Log(First(new int[] { 1 })); // => 1
}
private T First<T>(T[] xs) { return xs[0]; }
}
using UnityEngine;
using Tsukimi;
public class OvInferTwo : TsukimiBehaviour
{
void Start()
{
Debug.Log(Left(1, "a")); // => 1
}
private T1 Left<T1, T2>(T1 a, T2 b) { return a; }
}

T[][] のような入れ子の配列からも、要素の型が決まります。

using UnityEngine;
using Tsukimi;
public class OvInferNested : TsukimiBehaviour
{
void Start()
{
Debug.Log(Depth(new int[1][])); // => 1
}
private int Depth<T>(T[][] xs) { return xs.Length; }
}
using UnityEngine;
using Tsukimi;
public class OvBestCommon : TsukimiBehaviour
{
void Start()
{
long v = true ? 1 : 2L;
Debug.Log(v); // => 1
}
}
using UnityEngine;
using Tsukimi;
public class MemNestedType : TsukimiBehaviour
{
public struct Inner { public int V; }
void Start()
{
Inner i = new Inner();
Debug.Log(i.V); // => 0
}
}
using UnityEngine;
using Tsukimi;
public partial class R_part : TsukimiBehaviour
{
void Start()
{
Debug.Log(Helper());
}
}
public partial class R_part
{
private int extra;
int Helper()
{
extra = 41;
return extra + 1;
}
}
using UnityEngine;
using Tsukimi;
public abstract class MemAbstractBase : TsukimiBehaviour
{
public abstract int Get();
}
public class MemAbstractLeaf : MemAbstractBase
{
public override int Get() { return 1; }
void Start()
{
Debug.Log(Get()); // => 1
}
}

virtual のメソッドを override で上書きできます。

using UnityEngine;
using Tsukimi;
public abstract class MemVirtualBase : TsukimiBehaviour
{
public virtual int Get() { return 0; }
}
public class MemVirtualLeaf : MemVirtualBase
{
public override int Get() { return 1; }
void Start()
{
Debug.Log(Get()); // => 1
}
}

override した側から、基底に書いた実装を base で呼べます。

using UnityEngine;
using Tsukimi;
public abstract class MemBaseCallBase : TsukimiBehaviour
{
public int hits;
public virtual void Ring() { hits = hits + 1; }
}
public class MemBaseCallLeaf : MemBaseCallBase
{
public int extra;
public override void Ring()
{
base.Ring();
extra = extra + 1;
}
void Start()
{
Ring();
Debug.Log(hits); // => 1
Debug.Log(extra); // => 1
}
}