LoginSignup
2

More than 1 year has passed since last update.

posted at

Update your C# in Unity ~ nameof ~

Unityにおいて古いC#しか使えない時代もありました。しかし、それは過去のことです。本稿執筆時の最新LTSであるUnity 2019.4ではC# 7.3がサポートされています。また、本稿執筆時の最新Beta版であるUnity 2020.2ではC# 8.0がサポート予定です。

長らくUnityで古いC#しか使えなかったことで、「C#にこんな機能あるのか?知らなかった!」となることがある方も多いのではないでしょうか?この「Update your C# in Unity」シリーズでは、「C#の比較的新しい機能をUnityでこんな風に使えるよ!」という紹介を行います。


言語機能名: nameof
追加バージョン: C# 6.0
説明: 変数名、型名、メソッド・フィールド・プロパティなどのメンバ名を文字列リテラルとして取得する機能

利用例としては

  • SendMessageの第一引数など、メソッド名を求められる箇所で、文字列リテラルべた書きではなくて、nameofを使う
  • SerializedObjectのFindPropertyの第一引数など、フィールド名を求められる箇所で、文字列リテラルべた書きではなくて、nameofを使う

※ 個人的にはSendMessageの利用は避けるべきだと思っています。しかし、どうしようもない理由があって避けられない場合や、漸進的に改善をしていく必要がある場合、まずnameofで小さく改善するのがオススメです。

using UnityEngine;

public class EnemyLauncher : MonoBehaviour
{
    public void LaunchEnemy()
    {
        Debug.Log("Launched");
    }
}
using UnityEngine;

public class GameController : MonoBehaviour
{
    public void Start()
    {
        SendMessage(nameof(EnemyLauncher.LaunchEnemy));
    }
}

SendMessageやFindPropertyのように、メンバ(メソッドやフィールド)の名前を文字列リテラルとして引数にとる場合、コード中に文字列リテラルを直接埋め込むのではなく、nameofを使いましょう。

nameofを使うメリットは、「型名やメンバ名が変わった時に、対応する文字列リテラルの変更を変え忘れることが防止できる」ということです。

仮に、次のように文字列リテラルを直接引数として渡していて、使ってSendMessageを使っていたとします。

using UnityEngine;

public class GameController : MonoBehaviour
{
    public void Start()
    {
        // このように直接文字列リテラルを埋め込むのは避けるべき
        // EnemyLauncher型のLaunchEnemyメソッドの名前が変更された場合、実行時エラーになってしまう
        SendMessage("LaunchEnemy");
    }
}

この時、EnemyLauncher型のLaunchEnemyメソッドの名前が変えたとしましょう。同時に、GameControllerに直接埋め込まれている"LaunchEnemy"という文字列リテラルも変更しないといけません。しかし、これをうっかり変えそびれてしまうことがありえます。その場合、実行時エラーになってしまいます。このような実行時エラーは非常に厄介です。


一方で、次のように今回紹介するnameofを使っていた場合はどうでしょう?
EnemyLauncher型のLaunchEnemyメソッドの名前が変えた場合、GameController内のnameof内でコンパイルエラーになり、問題があることにすぐに気が付けます。
「メソッド名を変えたことが原因」の厄介な実行時エラーになる可能性を排除できます。
また、もしVisual SturioやRiderのリネーム機能でEnemyLauncher型のLaunchEnemyメソッドの名前が変えた場合、nameofの内部も自動的にリネームされ、非常に円滑にコードを編集することができます。

using UnityEngine;

public class GameController : MonoBehaviour
{
    public void Start()
    {
        // EnemyLauncher型のLaunchEnemyメソッドの名前が変更された場合、コンパイルエラーになり、厄介な実行時エラーの原因を事前に気付ける
        // また、IDEのリネーム機能を使った場合、↓の内容もリネーム対象となる
        SendMessage(nameof(EnemyLauncher.LaunchEnemy));
    }
}

このようにnameofを使うメリットは、「型名やメンバ名が変わった時に、対応する文字列リテラルの変更を変え忘れることが防止できる」ということです。


この投稿ではnameofのUnityでの利用例とそのメリットを説明しました。
なお、nameofのC#におけるより一般的な使い方は、INotifyPropertyChangedの実装や、ArgumentExceptionの引数に使うという利用方法です。
Unityにおいても、エラー文・警告文などでも使う場面があると思います。
変数名、型名、メソッド・フィールド・プロパティなどのメンバ名を文字列リテラルとして必要な場面では、積極的にnameofを使っていきましょう。

※ この投稿では、SendMessageを例にnameofを紹介しましたが、個人的にはSendMessageの利用は避けるべきだと思っています。しかし、どうしようもない理由があって避けられない場合や、漸進的に改善をしていく必要がある場合、まずnameofで小さく改善するのがオススメ。


関連・参考

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
What you can do with signing up
2