10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UnityのGetCompornent<T>()でNull条件演算子が使えない

Last updated at Posted at 2018-12-27

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さんのコメントを参照。(ありがとうございました!🙇🙇🙇)

(追記)参考、この辺に詳しい話が書かれてますね

10
7
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?