Unityのエディタからのみアクセス可能なパラメータを作りたい

## 経緯
厳密にはUnityのエディタからのみというより``` [assembly: AssemblyIsEditorAssembly] ```が指定されているアセンブリからのアクセスのみに限定するってやり方になる

何かしらのパラメータ定義のScriptableObjectなりJsonデータ用クラスなりを作って設定用エディタプログラムからは通常のpublicなプロパティのように振る舞い、それ以外の通常のゲームロジックからはgetのみにアクセスする...みたいなやり方をとりたい時に役に立ちそう

**参考ページ**
[Unityで「エディタからのみ外部アクセス可能なメンバ変数」を実現する方法の考察](https://qiita.com/yomogi_ft/items/ebd8cdcbf928a13f1f41)
[C# メソッドの呼び出し元メソッド名を取得するおまじない](https://qiita.com/hmuronaka/items/478bcf7ec792012c82c5)


## スクリプト

といっても参考ページのコピペみたいなものだが...
コードがかさばらないようにUtilityクラスみたいな形にしてチェック用メソッドを用意するのがいいかも


**チェック用ユーティリティクラス**

``` csharp

using UnityEngine;

namespace MyUtility
{
    public static class CallMethodChecker
    {

        /// <summary>
        /// 呼び出し元の関数が[assembly: AssemblyIsEditorAssembly]指定されてるコードから呼び出されているかのチェック.
        /// </summary>
        /// <returns></returns>
        public static bool CheckCalledFromEditor()
        {
            #if UNITY_EDITOR
            var method = new System.Diagnostics.StackFrame(2).GetMethod();
            if (method.DeclaringType.Assembly.IsDefined(typeof(AssemblyIsEditorAssembly), false) == false)
            {
                Debug.LogError($"Invalid Access! From{method.DeclaringType}::{method.Name}");
                return false;
            }
            else
            {
                return true;
            }
            #endif

            return false;
        }
        
        
        
        
    }
}

```

---
**何かしらのパラメータファイル**

``` csharp
using UnityEngine;

namespace sample
{
        [System.Serializable]
        public class Hoge
        {
            [SerializeField] string name;
            public string Name
            {
                get { return name; }
                set
                {
                    if (MyUtility.CallMethodChecker.CheckCalledFromEditor())
                        name = value;
                }
            }
            
            
            
            // コンストラクタ.
            public Hoge(
                string initName)
            {
                name = initName;
            }
        }
}

```

---

**何かしらのエディタスクリプトでのアクセス**
こちらからは通常のプロパティの用にアクセスしたい

``` csharp

using System;
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.Collections.Generic;
using System.IO;
using System.Text;


// 自身がエディタのアセンブリだという宣言.
[assembly: AssemblyIsEditorAssembly]
namespace sample
{

    public class HogeSettingEditor : EditorWindow
    {
         // 何かの処理とか.

        Hoge hogeData; // どこかでインスタンスを取得する.

        void OnGUI()
        {
            if (GUILayout.Button("HogeButton"))
            {
                hogeData.Name = "HogeName";
            }
        }

    }
}

```

---

**何かしらのゲームロジック側のスクリプト** 
こちらからのアクセスはしたくない

``` csharp

using UnityEngine;

namespace sample
{
    public class Sample : MonoBehaviour
    {

        Hoge hoge;

        void Awake()
        {
            hoge = new Hoge("jejeje");
        }
        
        void Start()
        {
            // こちら側でのアクセスはErrorを吐き出す.
            hoge.Name = "I Love Unity";
        }

        
        void Update()
        {
        }
    }
}


```

## まとめ


実際にエディタ側から呼び出しているかのチェックは ```CallMethodChecker```クラスの``` CheckCalledFromEditor()```メソッド内
呼び出し元のメソッドが```AssemblyIsEditorAssembly```属性が付与されたアセンブリからの呼び出しかを判定している
コールスタックに積まれているメソッドはこのチェックメソッドから見て二つ前なのでStackFrame()の引数は2を指定、1の場合はこのメソッドを読んでいるメソッド( 今回の場合だとNameプロパティのset内 )


``` csharp
        public static bool CheckCalledFromEditor()
        {
            #if UNITY_EDITOR
            var method = new System.Diagnostics.StackFrame(2).GetMethod();
            if (method.DeclaringType.Assembly.IsDefined(typeof(AssemblyIsEditorAssembly), false) == false)
            {
                Debug.LogError($"Invalid Access! From{method.DeclaringType}::{method.Name}");
                return false;
            }
            else
            {
                return true;
            }
            #endif

            return false;
        }

```

これをアクセスしたくない側のスクリプト( 今回の場合Sampleコンポーネント )から呼び出すと以下のようにエラーログを出す
![エラーが出る例.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212999/57c69c13-0f6b-4f82-58f3-6cdbccd3fe02.jpeg)


このチェックメソッドはUnityのエディタ側で呼び出すことを前提としているので実機の場合は #if 部分では弾いている、ゲームロジック部分からの呼び出しはエラーログが出るので善良なエンジニアはセッターは呼び出さないだろう...
肝心なところを人の裁量に任せちゃってる感がある
~~どのみち呼び出してもアプリが落ちるわけでもないし値を入れるわけではないので大丈夫そうではある~~


追記
今はやっぱReflection使えばいいんじゃね?ってなってます