TryGetComponentとout、out var のお話


##Unity 2019.2 から
`TryGetComponent` という `GetComponent` 相当のメソッドが追加されています。
このメソッドの紹介をしたいのですが、そのためには切っても切れない、 `out var(out変数宣言)` についてから書きたいと思います。
「out var ぐらい知ってらぁ！！」という方は、 [TryGetComponent](#trygetcomponent)からどうぞ。
「どっちも知ってらぁ！！」という方は・・・。お疲れ様でございました。

# out変数宣言

**out** 宣言。　使ってます？　多分、Unityでゲーム作っている上で自作のなんらかでこのキーワードをわざわざ使ってメソッド宣言している人はほとんどいないでしょう（偏見）

そもそもの機能としては、**「out を付けた引数で指定した変数はメソッド内で必ず結果が入りますよ。」**　という宣言です。

```csharp:outを使ったメソッド
        private void PlusMinusOne(int origin, out int plusResult, out int minusResult)
        {
            plusResult = origin + 1;
            minusResult = origin - 1; //out キーワードを付けた引数への代入が存在しない場合はエラー
        }
```

```csharp:呼び出し側
        public void Start()
        {
            int plusResult
            int minusResult;
            PlusMinusOne(100, out plusResult, out minusResult); //呼び出す方も out キーワードを付ける必要がある
            Debug.Log($"plusResult:{plusResult},minusResult:{minusResult}");
        }
```

```text:出力
plusResult:101,minusResult:99
```

ちなみに利点は、**「必ず値がセットされる事が保証される」** です。今回とは趣旨が違うので詳細は省きますが・・・[^1]

[^1]: 気になる人は、 `PlusMinusOne` メソッドの呼び出しをコメントアウトしてみてください。 エラーになります。

# Try\*\*
さて、自分でoutキーワードを使ったメソッドを作らないかもしれませんが、.netで用意されているクラスのメソッドにoutキーワードが使われている場合ももちろんあります。

(個人的に）一番使うであろうメソッドは　**Try系メソッド**です。

例えば、文字列をintに変換しようとした場合、`int.Parse("100");`のように、パースメソッドを呼びます。
しかし、例えば`int.Parse("ほげ");` こんなことをしたら変換に失敗してExceptionが発生してしまいます。
try~catchで括ってもいいですが、**先に変換可能かどうか調べつつ変換できないのかな？**。それ既にありますよ！！

```cs
bool int.TryParse(string s,out int result);
```

こんなのが用意されてます。　変換が出来る場合はメソッドの戻り値がtrueになり、さらにresultに結果が入ります。[^2]
出ました！**outキーワード**!!

[^2]: ほかにも `float.TryParse` や `DateTime.TryParse` など、Parse系メソッドはほぼ確実に `TryParse`メソッド が用意されています。

使う場合は

```csharp
int result = 0;
if(int.TryParse("ほげー",out result) == false){
    Debug.Log("変換できませんでした");
}else{
    Debug.Log($"変換結果:{result}");
}
```

こんな感じで、if文の中に入れて、戻り値で分岐させるのがよく見る使い方です。

#辛かったこと
さて、この`out`キーワードを使うのに辛かった事が2点あります。

①変数を先に宣言しなくてはいけない
②変数の宣言に（仕組み上)varが使いづらい

①はまぁ、格納先なので、当たり前として。　②は何かというと、`var`というやつは右辺から左辺の型を推論してくれる機能です。右辺が`int`なら`int`、`string`なら`string`に宣言してくれているわけです。

では、今回のケースに無理矢理`var`を使うとしたらどうなるでしょう。　`int`なので・・・。

```csharp
var plusResult = 0;
var minusResult = 0;
```

ってやります？　この**0**はどこから来たんだよという話で。
`var`を使いたいがために差し当たりの無い値0を持ってきた に過ぎなく、**手段と目的が逆転**してます。

#前置きが長かったね
それが、なんと、このように書けるようになります。

```csharp
if (int.TryParse("ぼげー", out var result) == false)
{
    Debug.Log("変換できませんでした");
}
else
{
    Debug.Log($"result:{result}");
}
```

やったー！　宣言が中に入った！！　そう、 `out` に指定する変数をその場で宣言できるようになりました！

注目してほしいのは、この

```csharp
else
{
    Debug.Log($"result:{result}");
}
```

この、elseブロックにも `result` が使われている事です。

for文の中で宣言した変数なんかは

```cs
for(var i = 0;i < 10;++i)
{
  Debug.Log(i); //スコープ内
}
Debug.Log(i); //スコープ外なのでエラー
```

このようにブロックがスコープ（生存範囲）になりますが、この`out変数宣言`はその**式が含まれているブロックがスコープ**になります。
まぁ、 **1行前に変数宣言があるのと同じ。** と考えておけば大体OKです。

##TryGetComponent
さてさて、ようやく `TryGetComponent` の話に移れます。
最初にも言いましたが、 Unity 2019.2 から `TryGetComponent` という `GetComponent` 相当のメソッドが追加されています。

```cs
bool TryGetComponent<T>(out T component)
```

今まで `GetComponent` は指定したComponentが取得できなかった場合は `null` が返ってくるので、それによって成否を判断していました。
それが、他の `Tryメソッド` 同様、 成否は`bool` を返すようになり、 `out変数` に直接結果を入れてくれる仕組みです。
また出た！**outキーワード**!! デモモウコワクナイ！

具体的には今まで

```csharp
        var sr = GetComponent<SpriteRenderer>();
        if (sr != null) //nullかどうかで成否判定
        {
            sr.color = Color.white;
        }
```

こうだったのが、TryGetComponentが追加されたこと、そして out変数宣言 が使えるようになったことで

```csharp
        if (TryGetComponent<SpriteRenderer>(out var sr)) //TryGetComponentの戻り値自体が 成否、out宣言で中身が入る
        {
            sr.color = Color.white;
        }
```

このようになります。

どっちが速いかーーーというと、正直あんまり差が無いらしいんですが・・・。([テラシュールブログ様参照](http://tsubakit1.hateblo.jp/entry/2019/07/16/233235))

#ちなみに

```cs
TryGetComponent<SpriteRenderer>(out var sr))
```

これは、Genericsの型パラメータに明示的に `SpriteRenderer` を渡しているので、 `var sr` というように、 `var` で **型推論** が効いている状態です。

逆に、**使用される型から型パラメータを型推論** することも出来るので、

```cs
TryGetComponent(out SpriteRenderer sr))
```

こう書いてもよいです。　
どちらを使うかは完璧好みでしょうから、お好きな方を使えばいいと思います。　僕は前者です。

え？

```cs
TryGetComponent(out var sr))
```

はダメなのかって？　**何をGetComponentするおつもりですか・・・？**

##補足

そういえば、今のところあまり見ませんが、

```csharp
public class Main : MonoBehaviour
{
    private SpriteRenderer sr;

    void Start()
    {
        if (TryGetComponent(out sr)) //メンバ変数に格納
        {
            sr.color = Color.white;
        }
    }
}
```

こういう書き方も出来るはずですよね。　変数宣言と `TryGetComponent` の箇所が離れすぎていると、**何をGetComponent**したのか一瞬戸惑いそうですけれど。

**しかし、これは案外アリかもしれません。**

僕はよく、Inspectorで**自分自身が持っているComponent**をセットさせる時に、(RequireComponentなど)

- 実行時に GetComponentは重いらしいから、あんまりやりたくないな。
- RequireComponent指定してあって、確実にそのComponentがあるってわかってるのにInspectorでわざわざドラッグ＆ドロップとかかったるいな。

って時に、

```cs
using UnityEngine;

[RequireComponent(typeof(SpriteRenderer))] //SpriteRendererを要求
public class ForceWhite : MonoBehaviour
{
    [SerializeField]
    private SpriteRenderer spriteRenderer;

    //このMonobehaviorをアタッチした瞬間、または コンテキストメニューから `Reset` を選んだ時に呼ばれる
    void Reset()
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
    }

    void Start()
    {
        spriteRenderer.color = Color.white;
    }
}
```

`Resetメソッド` を使って、半自動的にInspector参照を解決させるんですが
![アタッチした瞬間、SpriteRendererが自動でセットされるの図](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37184/f0966096-a7e8-0d9a-b194-1f27ab4eb1c2.gif)

```cs
    //このMonobehaviorをアタッチした時、または コンテキストメニューから `Reset` を選んだ時に呼ばれる
    void Reset()
    {
        TryGetComponent(out spriteRenderer); //呼びっぱなし
    }
```

そういう用途（Editor上でしか走らない箇所）であれば、こうやっちゃうのも悪くないのでは？？？（マサカリ案件）


#なんにせよ
用法用量を守って、ステキなUnityライフを。　それでは。