質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

2800閲覧

シングルトンライクなコードでnull判定する理由

退会済みユーザー

退会済みユーザー

総合スコア0

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2021/10/09 16:06

編集2021/10/09 16:08

前提・実現したいこと

以下のようなシングルトンみたなコード(それとも、これもシングルトンのコードと言えますか?)で、
null判定する理由は何でしょうか?
ご教示お願いします。

C#

1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 public class ItemBox : MonoBehaviour 6 { 7 public static ItemBox instance; 8 9 void Awake() 10 { 11 if (instance == null) 12 { 13 instance = this; 14 } 15 } 16 17 public void SetItem() 18 { 19 Debug.Log("SetItem"); 20 } 21 22 }

試したこと

以下のコードを試す前までは、
staticな変数は、ゲーム全体に変数が保存されることになるので、シーンが遷移してゲームオブジェクトが破棄されても
変数は生き残るようになっている
と認識していたため、
シーンをリロードした際に残っているinstanceがnullでないので、
そのために、「if (instance == null)」の条件判定が必要と思っていました。
しかし、以下のコードを試してみると、

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.SceneManagement; //追記。 5 6 7public class ItemBox : MonoBehaviour 8{ 9 public static ItemBox instance; 10 public static int i = 5; 11 12 void Awake() 13 { 14 Debug.Log(i); 15 if (instance == null) 16 { 17 Debug.Log(null); 18 instance = this; 19 }else{ 20 Debug.Log("exist"); 21 } 22 } 23 24 void Start() 25 { 26 i = 10; 27 Invoke("ReloadScene", 2.0f); 28 } 29 30 void ReloadScene() 31 { 32 SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex); 33 Debug.Log("Reload"); 34 } 35 36 public void SetItem() 37 { 38 Debug.Log("SetItem"); 39 } 40 41}

以下のようなログとなってしまいました。

5 Null SetItem Reload 10 Null SetItem

シーンをリロードしたら、instanceはnullとなってしまっているようです。
staticな変数でもシーンをリロードしたら、nullとなってしまうのでしょうか?
しかし、同じくstaticな変数iを用意して取っているログを見たところ、
シーンリロード時には値が10となっているので、リロード前の変数が残っているようにも見えます。
このことから、staticな変数がシーンを跨ぐと生き残るのか、破棄されるのかよくわからない状態です。
また、質問の前提に書きましたが、このシングルトンみたいなコードで「if (instance == null)」と判定する理由はなんでしょうか?
上記検証でわからなくなってしまったことに加えて、他に考えられることとしては、
上記シングルトンみたいなコードを複数のゲームオブジェクトにアタッチしたり、
1つだけのゲームオブジェクトにアタッチした場合でも、
Instantiateメソッド等でそのゲームオブジェクトを複数生成した場合に、
「if (instance == null)」の判定が生かされるようにも思えますが、
そもそもシングルトンみたいなコードを複数のゲームオブジェクトにアタッチしたり、
Instantiateメソッド等で複製すること自体があまりないように思えるので
(あったとしても開発者側(人間側)の凡ミスのはず)、
そのチェックのために行っているnull判定ではないように思えてしまいます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

instance == null で判定しているからです。

Unityのnullはnullじゃないかもしれない - Qiita

投稿2021/10/10 00:00

Zuishin

総合スコア28669

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2021/10/10 00:13 編集

C# には演算子のオーバーロードという機能があり、演算子の役割を書き換えることができます。 Monobehavior はこれを使って == を書き換えており、シーン変更などで破壊されたオブジェクトを null と判定するようにしているため、このようなことが起きます。 次のページは演算子のオーバーロードについての記事です。 https://ufcpp.net/study/csharp/oo_operator.html また、二つのオブジェクトを比較する際の概要を次の記事にまとめていますので、参照してください。 https://qiita.com/Zuishin/items/62c5b726bfa589b3fb9b これに加えて is を使う方法もあり、新しいバージョンの C# では instance is null で正確に判定できます。
退会済みユーザー

退会済みユーザー

2021/10/10 04:46

ご回答ありがとうございます。 今回は1570p様のご回答のほうが適切に思えたので、そちらにベストアンサーを付けさせていただきました。 instance is nullで試したところ、existのログが出力されることも確認しました。 ゲームオブジェクトを破棄したことを検知したいので、instance == nullで判定したいと判断しました (実際はnullになっていなくても、ゲームオブジェクトが破棄されたかを知りたい場合はinstance == nullが適切と思いました)。
Zuishin

2021/10/10 04:47

しまったお前だったか。
guest

0

ベストアンサー

私は素人なので正確ではない、間違っている部分もあるかもしれませんが、

staticな変数の中身がnullになっている、です。

ItemBoxクラスはstaticではないです。

リロードされたらゲームオブジェクトは破棄されます。

どこかのゲームオブジェクトにアタッチされているItemBoxも同然破棄されます。

staticな変数としてアクセス出来ますがinstanceの中身であるItemBoxは破棄されていますのではnullとなります。

ItemBoxのstaticな変数としてinstance(自身)を所持しますが、このItemBoxはただのクラスです。インスタンスが必要です。それをpublic static ItemBox instanceとして持っているって事で。
って感じでいいですかね?

public static ItemBox instance;
ItemBox.instanceはstaticな変数ですが、この中身はゲームオブジェクトにアタッチされたItemBoxクラスでありインスタンスが必要。

public static int i;
はItemBox.iですのでこれはstaticな変数でありインスタンスは必要ないです。

間違ってるかもしれませんが、MonoBehaviourを継承してたい、ゲームオブジェクトのコンポーネントとして扱いたい、staticなクラスにはしたくない、みたいな話かな?って思ってます。

投稿2021/10/09 23:31

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/10/10 04:46

ご回答ありがとうございます。 staticな変数で参照しているインスタンスが破棄されているため、nullと判定されるわけですね。 理解できました。 ありがとうございました。
Zuishin

2021/10/10 04:50

> public static int i; > はItemBox.iですのでこれはstaticな変数でありインスタンスは必要ないです。 低評価しました。
退会済みユーザー

退会済みユーザー

2021/10/10 05:05

Zuishin様、 いろいろ間違っているって事なのですね。勉強してきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問