

UnityのC#でゲームを作っています。  
IL2CPPという64ビットC++ビルドになった事でリフレクションを使用しないことになりました。

API通信周りを作成するに当たり、リフレクションを使用せず  
API受信データをベースとなるレスポンスクラスを継承した固有のクラスで  
キャストする必要があり、どうしてもできなかったのでテスト用クラスを  
作ってやってみようと思ったのですが方法がわからず悩んでおります。

下記クラスがあります。  
・基底クラスA  
・Aを継承したクラスBとC  
・LitJsonをシリアライズ・デシリアライズするテスト用クラスJsonTestManager  
・呼び出し元クラスをOnDebug

OnDebug内のOnClickButtonが実行されると  
ClassBとClassCにデータ作成され、  
わざとJsonTestManagerにあるClassA型のバッファにデータをセットしています。

下記部分で継承先の型を指定したいのですがどのようにして良いかわかりません。  
UnityだとC#3.0までなのでDynamaicが使用できず、リフレクションも使用不可になったので  
継承先のレスポンス型が変わった時に対応できないような状況です。

[code]

    testClassCC = LitJson.JsonMapper.ToObject<継承先の型>(str);
    
[/code]

■ClassA

[code]

    using UnityEngine;
    using System.Collections;
    
    public class ClassA
    {
        public int aaa;
        public int bbb;
    }
    
[/code]

■ClassB

[code]

    using UnityEngine;
    using System.Collections;
    
    public class ClassB : ClassA
    {
        public string test1;
        public string test2;
    }
    
[/code]

■ClassC

[code]

    using UnityEngine;
    using System.Collections;
    
    public class ClassC : ClassA
    {
        public string test3;
        public string test4;
    }
    
[/code]

■JsonTestManager

[code]

    using UnityEngine;
    using System.Text;
    using System.Collections;
    using LitJson;
    
    public class JsonTestManager
    {
        public ClassA testClassB;
        public ClassA testClassC;
        public ClassA testClassCC;
    
        public void JsonTest()
        {
            // 送信用データJsonStringに変換
            string litjsonString = LitJson.JsonMapper.ToJson(testClassC);
    
            byte[] postBytes = Encoding.Default.GetBytes(litjsonString);
    
            string str = Encoding.UTF8.GetString(postBytes);
    
            testClassCC = LitJson.JsonMapper.ToObject<継承先の型>(str);
        }
    }
    
[/code]

■呼び出し元クラスOnDebug--ボタンをタップするとOnClickButton()がコールされる。

[code]

    using UnityEngine;
    using System.Collections;
    
    public class OnDebug
    {
        public JsonTestManager jsonTestManager = new JsonTestManager();
    
        public void OnClickButton()
        {
            ClassB classB = new ClassB();
            classB.test1 = "test1";
            classB.test2 = "test2";
            ClassC classC = new ClassC();
            classC.test3 = "test3";
            classC.test4 = "test4";
    
            jsonTestManager.testClassB = classB;
            jsonTestManager.testClassC = classC;
            jsonTestManager.testClassCC = classC;
    
            jsonTestManager.JsonTest();
        }
    }
    
[/code]


CC BY-SA 3.0
2016-02-16T11:45:18.480
22173
2016-02-16T16:12:38.650
2016-02-16T16:12:38.650
76
5261
question
c# unity3d
リフレクションを使用せずにGetType()やType変数でキャストするには？


ジェネリッククラス・ジェネリックメソッドの型パラメータはコンパイル時に決定している必要があるので、リフレクションを使わない限りType型などから動的に型を指定することはできません。

ただ、実行時に型を変化させる必要はなく、`JsonTestManager`
を利用する側から型を決められるようにしたいということであれば、`JsonTestManager` ごとジェネリックにすることで解決できそうです。

質問に書かれたコードをジェネリックを使って愚直に書き換えると、こんな感じでしょうか。

[code]

    public class JsonTestManager<T1,T2,T3>
    {
        public T1 testClassB;
        public T2 testClassC;
        public T3 testClassCC;
    
        public void JsonTest()
        {
            string litjsonString = LitJson.JsonMapper.ToJson(testClassC);
            // DefaultかUTF8か、どちらかに統一すべきでは・・・？
            byte[] postBytes = Encoding.Default.GetBytes(litjsonString);
            string str = Encoding.UTF8.GetString(postBytes);
            testClassCC = LitJson.JsonMapper.ToObject<T3>(str);
        }
    }
    
    public class OnDebug
    {
        public void OnClickButton()
        {
            ClassB classB = new ClassB();
            classB.test1 = "test1";
            classB.test2 = "test2";
            ClassC classC = new ClassC();
            classC.test3 = "test3";
            classC.test4 = "test4";
    
            var jsonTestManager = new JsonTestManager<ClassB, ClassC, ClassC>();
    
            jsonTestManager.testClassB = classB;
            jsonTestManager.testClassC = classC;
    
            jsonTestManager.JsonTest();
        }
    }
    
[/code]

~~もし「testClassBをJSONに変換して、再度オブジェクトに戻したものを返す」だけなら(略~~ ではないようなので削除しました。

あるいは `ToObject<T>()` さえなんとかできればいいのなら、フィールドは `ClassA` のままにして、`ToObject<T>()`
に渡す型パラメータを `JsonTest()` に渡す方法もあります。シングルトンにしたい、あるいはインスタンスを使いまわしたいならこの方が手軽ですね。

[code]

    public class JsonTestManager
    {
        public ClassA  testClassB;
        public ClassA  testClassC;
        public ClassA  testClassCC;
    
        public void JsonTest<TResult>()
        {
            string litjsonString = LitJson.JsonMapper.ToJson(testClassC);
            byte[] postBytes = Encoding.Default.GetBytes(litjsonString);
            string str = Encoding.UTF8.GetString(postBytes);
            testClassCC = LitJson.JsonMapper.ToObject<TResult>(str);
        }
    }
    
    public class OnDebug
    {
        public JsonTestManager jsonTestManager = new JsonTestManager();
    
        public void OnClickButton()
        {
            ClassB classB = new ClassB();
            classB.test1 = "test1";
            classB.test2 = "test2";
            ClassC classC = new ClassC();
            classC.test3 = "test3";
            classC.test4 = "test4";
    
            jsonTestManager.testClassB = classB;
            jsonTestManager.testClassC = classC;
    
            jsonTestManager.JsonTest<ClassC>();
    
            // フィールドの型はClassAなので、派生型として扱うならキャストが必要
            var classCC = (ClassC)jsonTestManager.testClassCC;
        }
    }
    
[/code]


CC BY-SA 3.0
2016-02-16T13:12:59.637
22179
2016-02-16T15:56:41.770
2016-02-16T15:56:41.770
8000
8000
22173
answer