C#
Unity

C#のプロパティの用法についての思案メモ


書き出し

とあるUnityのフレームワークの中で見つけたコードです。

int Counter;

void Update()
{
if (Counter > 100)
{
// カウントが閾値を超えたときの処理
}
}

なぜCounterに値を代入した際にチェックしないでUpdateで毎フレームチェック1しているのか……謎。

こういうときはプロパティを使ったほうがいいのでは……と思ったのですが、自分もプロパティってあまり使ったことがないなーと思ったので自分が思いつくなりの用法をメモします。

ざっと調べた感じ、プロパティの使い方についての記事は出てきても「どう使うか」を実際に解説した記事は見当たらなかったので。

プロパティとはなんぞや、という方は以下の記事を参照。

プロパティ - C# によるプログラミング入門 | ++C++; // 未確認飛行 C


使い方メモ


リスナの登録管理

private bool _isListening = false;

public bool IsListening
{
get => _isListening;
set
{
if (_isListening == value)
{
return;
}

_isListening = value;
if (_isListening)
{
ExampleEvents.ExampleEvent += ExampleEventHandler;
}
else
{
ExampleEvents.ExampleEvent -= ExampleEventHandler;
}
}
}

IsListeningtruefalseを入れるだけでリスナの登録を管理できます。いろんなタイミングでリスナを登録/解除しているとカオスになるので、これを使うとかなり楽になります。探すときもIsListeningを検索するだけでいいし。


ログ出し

public enum BadStatus

{
None,
Poison,
Paralyze,
}

private BadStatus _status = BadStatus.None;

public BadStatus Status
{
get => _status;
set
{
Debug.Log($"{_status} => {value}");
_status = value;
}
}

enumでStateを定義するのはよくあることだと思います。

以下のように変化させると

Status = BadStatus.Poison;

Status = BadStatus.Paralyze;
Status = BadStatus.None;

こんな感じでログが出ます。


ログ

None => Poison

Poison => Paralyze
Paralyze => None

ステート遷移の解析に役立ちます。重要なのはNone => Noneなど、同じステートへの変化でもログを省略しないこと。

うっとうしいですがその方が解析が楽です。


値のバリデート

public readonly int MaxHp = 200;

public int _hp;

public int HP
{
get => _hp;
set
{
if (value < 0)
{
value = 0;
}
else if (value > MaxHp)
{
value = MaxHp;
}

Debug.Log($"{_hp} => {value}");
_hp = value;
}
}

ゲームでよくあるHPの管理。

ダメージを受けたり回復されたり。

HP = 100;

HP -= 300;
HP += 10;
HP += 999999999;

どれだけ食らっても一定の範囲内に収まります。


ログ

0 => 100

100 => 0
0 => 10
10 => 200


だんだん状態異常が効かなくなってくるやつ

public int ResistancePoison = 40;

public int _accumulatedPoison = 0;

public int AccumulatedPoison
{
get => _accumulatedPoison;
set
{
_accumulatedPoison = value;
if (_accumulatedPoison > ResistancePoison)
{
Status = BadStatus.Poison;
_accumulatedPoison = 0;
ResistancePoison += 20;
}
}
}

毒の蓄積値が閾値以上になると値をリセットして毒状態になり、閾値を大きくします。

AccumulatedPoison += 50;

Debug.Log("Cure!");
Status = BadStatus.None;
AccumulatedPoison += 50;
Debug.Log("again...");
AccumulatedPoison += 50;


ログ

None => Poison

Cure!
Poison => None
again...
None => Poison


感想

めっちゃバグりそう

値のバリデートやログ出し程度に留めておかないと変な穴2にハマって死にそうですね。

あとクラスのメンバ変数をクラスの上に書く基本のスタイルだと、変数の部分にロジックが混ざってめっちゃ読みづらそうです。

最近はIDEがかしこいので変数とメソッドを取り混ぜて書いても3なんとかなりますが、なんとかなるってだけでつらいです。すごくつらい。

なんかいい使い方あるよって方はなんか書いてわたしの蒙を啓いてください。

おしまい。





  1. 処理をUpdateのタイミングで行う必要もない... 



  2. kotlinだとfield知らないとしぬ 



  3. いやいるんですよそんなことする奴……いるんですよ! しかも新しく書いたやつから下に書いてるだけで特に並びに関連性があるわけでもなく……