2018.3でC#6が昇格(?)して、便利になりました。
しかし
var r = GetComponent<Rigidbody>();
if(r != null)
{
// Rigidbodyがアタッチされていないとここは通れらない
r.AddForce(force, mode);
}
// 一方で・・・
GetComponent<Rigidbody>()?.AddForce(force, mode);
// MissingComponentException発生!
ゲームオブジェクトに type がアタッチされている場合は type のタイプを使用してコンポーネントを返します。ない場合は null です
https://docs.unity3d.com/ja/current/ScriptReference/Component.GetComponent.html
なんでやねん!
どうもGetComponent<T>()
で帰ってくるnullは真正のnullではないみたいです。デバッカで見ると{null}
となっています。
発生している例外もNullRefarenceException
ではありません。
C# 6で導入されたnull条件演算子(?.)ですが、以下の2つの式がほぼ同じ意味になります。
x != null ? x.M() : null
x ?.M()
「ほぼ」であって「完全に同じ」と言えないのは、==演算子を呼ぶか呼ばないかが変わってしまうせいです。 前者(自分で==を呼んでいるやつ)はオーバーロードされた==を呼び出しますが、 後者(?.を利用)は呼びません(直接nullかどうか調べます)。
https://ufcpp.net/blog/2016/12/tipsnulloperation/
==
がオーバロードされています。
(追記)どうしてもnull条件演算子が使いたい!!
UnityObject版null -> 正真正銘のnullに変換する操作を拡張メソッドで隠蔽する方法があるそうです。
本来のnull条件演算子だけに比べると少し長くなってしまいますが、それでもif(component!=null)
で囲むよりは幾分か短く書くことが出来ます。
public static T NullCast<T>(this T obj) where T : UnityEngine.Object
=> (obj != null) ? obj : (System.Object)null;
GetComponent<Rigidbody>().NullCast()?.AddForce(force, mode); // 推論が効くはず
詳細は@albireoさんのコメントを参照。(ありがとうございました!🙇🙇🙇)
(追記)参考、この辺に詳しい話が書かれてますね