Unity_使用反射實現一個SendMessageUpwards

關於Invoke的一些方法可以看我上篇博客-->>使用反射完成一個Invoke(其實我感覺應該是SendMessage)

https://blog.csdn.net/MikuLingSSS/article/details/83422814

============================================代碼================================================

       因爲就是那上篇的代碼進行的擴展,所以這些代碼會連着上篇的代碼,

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

//SendMessageUpward<-OR->BroadcastMessage使用多線程,先在主線程中找到所有本級物體以及父級物體上面的所有Mono組件,壓入一個parent列表
//之後新建一個線程,在裏面進行遞歸,如果找到方法就把我們找到的數據暫時的壓進一個dict<className,list<methodName>>中,在parent爲空的時候,我們就可以遍歷這個dict來進行數據的操作
//感覺這個想法可行
//(上面這段話是我上篇博客最後留下的,但是實現沒有用到線程,因爲我測試了一下代碼的延遲,發現根本沒有用到線程的必要,所以pass(其實還是因爲有幾個難點懶得去思考 = = ,比如join,比如併發查詢,執行))

public static class InvokeExtension
{
    #region SendMessageUpward
    /// <summary>
    /// 查找到所有的繼承了Mono的自身以及父級物體組建
    /// </summary>
    /// <param name="transform"></param>
    /// <param 需要反射的方法名="method_name"></param>
    /// <param 參數和參數類型的列表="obj"></param>
    /// <returns></returns>
    public static object SelfInvokeUpward(this Transform transform, string method_name, params object[] obj)
    {
        List<Type> class_name_list = new List<Type>();
        Transform trans = transform;
        Type[] type_list = new Type[obj.Length / 2];
        object[] obj_list = new object[obj.Length / 2];
        for (int i = 0; i < obj.Length; i++)
        {
            if (i % 2 == 0)
            {
                type_list[i / 2] = (Type)obj[i];
                continue;
            }
            obj_list[i / 2] = obj[i];
        }
        while (trans.parent != null) // 一步步遞歸到最上層,並獲取這裏面繼承了Mono的腳本
        {
            trans = trans.parent;
            if (trans.parent == null)
            {
                Component[] thisComponent = trans.GetComponents(typeof(MonoBehaviour));
                class_name_list.AddClass_Type(thisComponent);
            }
            
            for (int l = 0; l < trans.childCount; l++)
            {
                Component[] childComponent = trans.GetChild(l).GetComponents(typeof(MonoBehaviour));
                class_name_list.AddClass_Type(childComponent);
            }
            
        }
        List<SaveClass_Method> temp = class_name_list.SelectClassData(method_name, obj_list, type_list);
        List<object> return_obj_list = new List<object>();
        for (int i = 0; i < temp.Count; i++)
        {
            return_obj_list.Add(temp[i]._class_name.GetMethod(method_name, type_list).Invoke(temp[i]._instance, obj_list));
        }
        return return_obj_list; // 返回值列表,object類型
    }

    /// <summary>
    /// 通過Type返回對象的instance typeof(Class_name) 
    /// </summary>
    /// <param name="sel"></param>
    /// <param 我們需要找到的方法名="method_name"></param>
    /// <param 參數列表="obj"></param>
    /// <param 參數類型列表="type"></param>
    /// <returns></returns>
    private static List<SaveClass_Method> SelectClassData(this List<Type> sel, string method_name, object[] obj, Type[] type)
    {
        List<SaveClass_Method> t = new List<SaveClass_Method>();
        for (int i = 0; i < sel.Count; i++)
        {
            foreach (MethodInfo item in sel[i].GetMethods())
            {
                if (item.Name == method_name && item.GetParameters().Length == obj.Length && IsConsistent(item.GetParameters(), type))
                {
                    //這個結構體在最下面
                    SaveClass_Method save_class = new SaveClass_Method();
                    save_class._instance = GetInstance(sel[i]);
                    save_class._class_name = sel[i];
                    t.Add(save_class);
                }
            }
        }
        return t;
    }
    /// <summary>
    /// 獲得當前組建的所有繼承Mono的類
    /// </summary>
    private static void AddClass_Type(this List<Type> list, Component[] com)
    {
        for (int i = 0; i < com.Length; i++)
        {
            list.Add(Type.GetType(com[i].GetType().ToString()));
        }
    }

    #endregion

    #region Invoke 以下是上篇博客代碼
    public static object SelfInvoke(this Transform transform, string methodName, params object[] params_obj)
    {
        object obj = null;
        Component[] component = transform.GetComponents(typeof(MonoBehaviour));
        for (int i = 0; i < component.Length; i++)
        {
            Type class_name = Type.GetType(component[i].GetType().ToString());
            Iteration(class_name, methodName, ref obj, params_obj);
        }
        return obj;
    }

    private static void Iteration(Type class_name, string methodName, ref object obj, params object[] params_obj)
    {
        Type[] type;
        object[] params_obj_obj;
        if (params_obj.Length == 0 || params_obj == null)
        {
            type = new Type[] { };
            params_obj_obj = new object[] { };
        }
        else
        {
            type = new Type[params_obj.Length / 2];
            params_obj_obj = new object[params_obj.Length / 2];
            for (int i = 0; i < params_obj.Length; i++)
            {
                if (i % 2 == 0)
                {
                    type[i / 2] = (Type)params_obj[i];
                    continue;
                }
                params_obj_obj[i / 2] = params_obj[i];
            }
        }
        foreach (MethodInfo item in class_name.GetMethods())
        {
            if (item.Name == methodName && item.GetParameters().Length == type.Length && IsConsistent(item.GetParameters(), type))
            {
                object instance = GetInstance(class_name);
                obj = class_name.GetMethod(methodName, type).Invoke(instance, params_obj_obj);
            }
        }
    }

    private static bool IsConsistent(ParameterInfo[] info, Type[] type) //
    {

        for (int i = 0; i < type.Length; i++)
        {
            if (info[i].ParameterType != type[i])
            {
                return false;
            }
        }
        return true;
    }

    private static object GetInstance(Type t)
    {
        return Activator.CreateInstance(t);
    }

    #endregion

    #region Font Size And Color
    // 下面都是富文本顏色,就不說了
    public static string Str_Red(this string str, int size = 12)
    {
        return "<color=#ff0000><size=" + size + ">" + str + "</size></color>";
    }

    public static string Str_Green(this string str, int size = 12)
    {
        return "<color=#00ff00><size=" + size + ">" + str + "</size></color>";
    }

    public static string Str_Rand(this string str, int size = 12)
    {
        string color_16 = "";
        for (int i = 0; i < 3; i++)
        {
            color_16 += Convert.ToString(UnityEngine.Random.Range(0, 255), 16);
        }
        return "<color=#" + color_16 + "><size=" + size + ">" + str + "</size></color>";
    }

    public static string Str_Blue(this string str, int size = 12)
    {
        return "<color=#0000ff><size=" + size + ">" + str + "</size></color>";
    }
    #endregion

}

// 這是我們需要保存的結構
public struct SaveClass_Method
{
    public object _instance;
    public Type _class_name;
}

調用代碼:

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

public class Run_Test_Scripts : MonoBehaviour
{
    public GameObject game_obj;
    void Start()
    {
        transform.SelfInvokeUpward("Test", typeof(string), "this is sibada!!!");
        transform.SelfInvokeUpward("Test", typeof(int), 133, typeof(int), 144, typeof(string), "-QAQ-");
        transform.SelfInvokeUpward("Test", typeof(GameObject), game_obj);
    }
}

其他的類代碼:

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

// Cube_Test_prefab1,2,header代碼都一樣,不過Cube_Test_prefab_2 多出一個使用GameObject參數的重載
public class Cube_Test_prefab_2 : MonoBehaviour {

    public string Name
    {
        get
        {
            return typeof(Cube_Test_prefab_3).ToString();
        }
    }

    public void Test(string _str)
    {
        Debug.Log(Name.Str_Red() + "->(string)->" + _str.ToString().Str_Blue());
    }

    public void Test(int _int)
    {
        Debug.Log(Name.Str_Red() + "->(int)->" + _int.ToString().Str_Blue());
    }

    public void Test(int _int, int _int2, string _str)
    {
        Debug.Log(Name.Str_Red() + "->(int,int,int)->".Str_Red() + ((_int + _int2) + _str).Str_Blue());
    }

    // 就是這個重載,
    public void Test(GameObject game_obj)
    {
        Debug.Log(game_obj.name);
        game_obj.transform.position = new Vector3(1, 0, 0);
    }

}

Unity Scene結構:

運行結果:::

================================================================================================

        可以看到,在最後錄製的時候,爆出了幾個Ctor的錯誤,這些應該是在CreateInstance的時候出現的,目前不清楚怎麼修 = = ,而且我在CubeHeader。。。這幾個腳本里面無法使用gameobject.name  transform.name 這些方法,Unity會直接拋出Null錯誤,而this.ToString()則是直接返回一個Null。。。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章