Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9529

[C#]コンストラクタを呼ばずにインスタンスを作る

$
0
0

以下のようなクラスがあるとき、インスタンスの作成にとても時間がかかってしまいます。

publicclassHoge{privateintv;publicintValue=>v;publicHoge(){// Application.isPlayingはメインスレッドで呼ばなければ例外が発生するDebug.Log($"Application.isPlaying:{Application.isPlaying}");// コンストラクタで重い処理をしているv=HeavyFunc();}privateintHeavyFunc(){// 重い初期化処理Thread.Sleep(5000);// 計算結果return42;}}

インスタンスを作成するときにメインスレッドで行ってしまうとUIが止まってしまうのでできれば別スレッドで作成したいところです。
しかし、コンストラクタ内部でApplication.isPlayingにアクセスしてしまっているため通常はメインスレッドでしか作成することができません。

Task.Run(()=>{try{varh=newHoge();Debug.Log(h.Value);}catch(Exceptione){// UnityException: get_isPlaying can only be called from the main thread.// Constructors and field initializers will be executed from the loading thread when loading a scene.// Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.Debug.LogException(e);}});

このクラスを書いたのが自分であれば修正すればいいですがソースコードを修正できない場合もあります。
そのような場合、最終手段として
System.Runtime.Serialization.FormatterServices.GetUninitializedObject
を使うことでコンストラクタを呼ばずにインスタンスを作成することができます。
インスタンスさえ作成できれば後はリフレクションで何とかなります。

// privateなフィールド、メソッドにアクセスするためにリフレクションを使用するvarvInfo=typeof(Hoge).GetField("v",BindingFlags.NonPublic|BindingFlags.Instance);varheavyFuncInfo=typeof(Hoge).GetMethod("HeavyFunc",BindingFlags.NonPublic|BindingFlags.Instance);_=Task.Run(()=>{try{// コンストラクタを呼ばずにインスタンスを作成varhoge=FormatterServices.GetUninitializedObject(typeof(Hoge))asHoge;// HeavyFuncを実行するvarresult=heavyFuncInfo.Invoke(hoge,null);// フィールドに値をセットvInfo.SetValue(hoge,result);// 正しくインスタンスが作成されているDebug.Log(hoge.Value);}catch(Exceptione){Debug.LogException(e);}});

Viewing all articles
Browse latest Browse all 9529

Trending Articles