[Unity] 判断一个变量的反射类型是否是指定泛型

295 阅读1分钟

定义泛型的脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyClass<T>
{
    public T value;
}

public class MyIntClass : MyClass<int>
{
}

1.不能使用 fields[i].FieldType == typeof(MyClass)

用于测试的 Mono 脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System.Linq;

public class TestMono : MonoBehaviour
{
    private MyIntClass myIntIns = new MyIntClass();

    void Start()
    {
        var fields = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        Debug.LogError(fields[0].FieldType);
        Debug.LogError(typeof(MyClass<int>));
        Debug.LogError(fields[0].FieldType == typeof(MyClass<int>));
    }
}

Log

MyIntClass
UnityEngine.Debug:LogError (object)
TestMono:Start () (at Assets/Scenes/TestMono.cs:18)

MyClass`1[System.Int32]
UnityEngine.Debug:LogError (object)
TestMono:Start () (at Assets/Scenes/TestMono.cs:19)

False
UnityEngine.Debug:LogError (object)
TestMono:Start () (at Assets/Scenes/TestMono.cs:20)

可见,直接使用 typeof(MyClass<XXX>) 与反射得到的 MyClass<XXX> 类型的变量的 FieldType 相比较是不行的

2.不能使用 typeof(MyClass<>).IsAssignableFrom(fields[i].FieldType)

用于测试的 Mono 脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System.Linq;

public class TestMono : MonoBehaviour
{
    private MyIntClass myIntIns = new MyIntClass();

    void Start()
    {
        var fields = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        Debug.LogError(typeof(MyClass<>));
        Debug.LogError(fields[0].FieldType);
        Debug.LogError(typeof(MyClass<>).IsAssignableFrom(fields[0].FieldType));
    }
}

Log

MyClass`1[T]
UnityEngine.Debug:LogError (object)
TestMono:Start () (at Assets/Scenes/TestMono.cs:18)

MyIntClass
UnityEngine.Debug:LogError (object)
TestMono:Start () (at Assets/Scenes/TestMono.cs:19)

False
UnityEngine.Debug:LogError (object)
TestMono:Start () (at Assets/Scenes/TestMono.cs:20)

3.可以用 fields[0].FieldType.BaseType.GetGenericTypeDefinition() == typeof(MyClass<>)

用于测试的 Mono 脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System.Linq;

public class TestMono : MonoBehaviour
{
    private MyIntClass myIntIns = new MyIntClass();

    void Start()
    {
        var fields = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        Debug.LogError(typeof(MyClass<>));
        Debug.LogError(fields[0].FieldType.BaseType.GetGenericTypeDefinition());
        Debug.LogError(fields[0].FieldType.BaseType.GetGenericTypeDefinition() == typeof(MyClass<>));
    }
}

Log

MyClass`1[T]
UnityEngine.Debug:LogError (object)
TestMono:Start () (at Assets/Scenes/TestMono.cs:18)

MyClass`1[T]
UnityEngine.Debug:LogError (object)
TestMono:Start () (at Assets/Scenes/TestMono.cs:19)

True
UnityEngine.Debug:LogError (object)
TestMono:Start () (at Assets/Scenes/TestMono.cs:20)

但是 GetGenericArguments() 只能用于泛型的 type

如果用于非泛型的 type 就会报错

InvalidOperationException: This operation is only valid on generic types.
System.RuntimeType.GetGenericTypeDefinition () (at <75633565436c42f0a6426b33f0132ade>:0)
TestMono+<>c.<Start>b__2_0 (System.Reflection.FieldInfo field) (at Assets/Scenes/TestMono.cs:19)
System.Linq.Enumerable+WhereArrayIterator`1[TSource].MoveNext () (at <1c318258bf0843289b0e2cbe692fee39>:0)
TestMono.Start () (at Assets/Scenes/TestMono.cs:19)

所以要先加一个是否是泛型的判断

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;

public class TestMono : MonoBehaviour
{
    private MyIntClass myIntIns = new MyIntClass();

    private int testint = 0;

    // Start is called before the first frame update
    void Start()
    {
        var fields = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        myIntIns.value = 114514;

        foreach (var field in fields)
        {
            if (field.FieldType.BaseType is not { IsGenericType: true }) continue;
            if (field.FieldType.BaseType.GetGenericTypeDefinition() == typeof(MyClass<>))
            {
                var var_reflected = (MyClass<int>)field.GetValue(this);
                Debug.LogError(var_reflected.value);
            }
        }
    }
}