Unity C# 游戏开发 反射 Reflection 案例讲解(图文详细,带源码)

Posted 水光涵月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity C# 游戏开发 反射 Reflection 案例讲解(图文详细,带源码)相关的知识,希望对你有一定的参考价值。

今天打球的小姐姐格外。。。

小姐姐为了感谢我最近的付出,邀请我一块打球,那我必须得把把赢她(钢铁直男的气势不能丢),不能给程序员丢脸,我被眼前的球晃的好晕🙈,很快小姐姐也没力气了,坐在了地上,说最近被反射搞得好迷糊🙈。

那我肯定不能惯着她😎,反射下,看小姐姐的脚本里都写了啥!!😎😎😎💛😻😻



一、反射是什么?

我们先来个官方的解释:这是官方的文档文档链接

反射提供了描述程序集、模块和类型的对象(类型为Type)。您可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果您在代码中使用属性,反射使您能够访问它们。

讲完之后,小姐姐的状态是这样的:

相信大家也有这种感觉,这都说的是啥?
用我自己的理解来解释:反射可以让你知道一个程序集里面的构造函数,字段,属性,方法,等等。知道了这些,你就可以去创建相应的对象了。
接下来就用我偷偷从小姐姐那拷过来的脚本来练练手。


二、反射怎么用?

我们直接用小姐姐的脚本来一块学习下

1.要反射的目标脚本内容

下面就是小姐姐脚本的全部内容,里面有字段,属性,构造函数,方法,我们可以先不看里面写的啥,一会用反射就都可以看到啦!😜

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

public class ReflectionTest
{
    /// <summary>
    /// 排名
    /// </summary>
    public int ranking;
    /// <summary>
    /// 名字
    /// </summary>
    private string m_name;
    /// <summary>
    /// 长度
    /// </summary>
    private string m_length;
    /// <summary>
    /// 形状
    /// </summary>
    private string m_shape;

    #region 构造函数
    public ReflectionTest(string name, string length)
    {
        this.m_name = name;
        this.m_length = length;
    }
    public ReflectionTest(string name,string shape, string length)
    {
        this.m_name = name;
        this.m_shape = shape;
        this.m_length = length;
    }

    public ReflectionTest(string shape)
    {
        this.m_shape = shape;
    }

    public ReflectionTest()
    {
        
    }

    #endregion
   
    #region 属性

    /// <summary>
    /// 名字
    /// </summary>
    public string Name
    {
        get => m_name;
        set => m_name = value;
    }

    /// <summary>
    /// 长度
    /// </summary>
    public string Length
    {
        get => m_length;
        set => m_length = value;
    }

    /// <summary>
    /// 形状
    /// </summary>
    public string Shape
    {
        get => m_shape;
        set => m_shape = value;
    }

    #endregion
    
    /// <summary>
    /// 信息打印出来
    /// </summary>
    public void ShowContent()
    {
        Debug.Log("姓名:" + m_name + "\\n" + "形状:" + m_shape + "---" + "长度:" + m_length);
    }
    /// <summary>
    /// 打印排名
    /// </summary>
    public void ShowRanking()
    {
        Debug.Log("排名是:"+ranking);
    }
    /// <summary>
    /// 要开始发动啦!!
    /// </summary>
    public void StartMove()
    {
        Debug.Log(m_name+"要开始发动啦!!");
    }
}

💥💥接下来就让我们大展身手

2.反射的实际应用

我就举几个比较常用的方法,抛砖引玉

感兴趣的小伙伴可以根据官方文档去做更多的实践。要永远相信,官方文档是最全面的,文档链接在上面发了。
首先我们创建个脚本,挂载到空物体上

在脚本中实例化要反射的小姐姐脚本。

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

/// <summary>
/// 反射的相关测试
/// </summary>
public class FindOfReflection : MonoBehaviour
{
    private ReflectionTest reflectionTest;

    private void Awake()
    {
        reflectionTest = new ReflectionTest();
    }
}

1).获取构造函数的所有参数及参数的数据类型

private void Start()
    {
         SeeConstructor();
    }
 /// <summary>
    /// 获取构造函数的所有参数及参数的数据类型
    /// </summary>
    private void SeeConstructor()
    {
        //获取reflectionTest的Type
        Type type = reflectionTest.GetType();
        //通过Type获取这个类的所有构造函数信息
        ConstructorInfo[] constructorArray = type.GetConstructors();
        foreach (ConstructorInfo constructorInfo in constructorArray)
        {
            //获取每个构造函数的所有参数
            ParameterInfo[] parameterArray = constructorInfo.GetParameters();
            foreach (ParameterInfo parameterInfo in parameterArray)
            {
                Debug.Log("数据类型:"+parameterInfo.ParameterType.ToString()+"\\n"+"参数名字:"+parameterInfo.Name);
            }
        }
    }

🌵执行结果如下

2).通过反射获取属性

 private void Start()
    {
         SeeProperty();
    }
 /// <summary>
    /// 通过反射获取属性
    /// </summary>
    private void SeeProperty()
    {
        //获取reflectionTest的Type
        Type type = reflectionTest.GetType();
        //获取所有属性信息
        PropertyInfo[] propertyInfos = type.GetProperties();
        foreach (PropertyInfo propertyInfo in propertyInfos)
        {
            //打印出来属性的名字
            Debug.Log("属性:"+propertyInfo.Name);
        }
    }

🌵执行结果如下

3).查看类中的公开方法

 private void Start()
    {
         SeePublicMethod();
    }
      /// <summary>
    /// 查看类中的公开方法
    /// </summary>
    private void SeePublicMethod()
    {
        Type type = reflectionTest.GetType();
        //通过type获取所有公开方法的信息
        MethodInfo[] methodInfos = type.GetMethods();
        foreach (MethodInfo methodInfo in methodInfos)
        {
            Debug.Log("公开方法的返回类型:"+methodInfo.ReturnType+"---"+"方法的名字:"+methodInfo.Name);
        }
    }

🌵执行结果如下

4).查看类中的公开字段

 private void Start()
    {
         SeePublicField();
    }
     /// <summary>
    /// 查看类中的公开字段
    /// </summary>
    private void SeePublicField()
    {
        Type type = reflectionTest.GetType();
        //通过type获取所有公开的字段的信息
        FieldInfo[] fieldInfos = type.GetFields();
        foreach (FieldInfo fieldInfo in fieldInfos)
        {
            Debug.Log("公开的字段的名字:"+fieldInfo.Name);
        }
    }

🌵执行结果如下

中断一下,我感觉这小姐姐的脚本不对劲,你们回头看下反射出来的数据,难道。。😱

5).通过反射用构造函数动态生成对象

那我们就将计就计,生成几个符合小姐姐的对象吧

 private void Start()
    {
         CreatObjectByConstruct();
    }
     /// <summary>
    /// 通过反射用构造函数动态生成对象
    /// </summary>
    private void CreatObjectByConstruct()
    {
        Type type = reflectionTest.GetType();
        Type[] typeArray ={typeof(string), typeof(string),typeof(string)};
        //根据构造函数参数类型来获取构造函数
        ConstructorInfo constructorInfo = type.GetConstructor(typeArray);
        //要传入的参数
        object[] objectArray={"王二","蘑菇","8cm"};
        //调用构造函数来生成对象
        object obj = constructorInfo.Invoke(objectArray);
        //调用打印方法,看是否有输出
        ((ReflectionTest)obj).ShowContent();
    }

🌵执行结果如下

6).通过反射用Activator静态生成对象

再来一个!

 private void Start()
    {
         CreatObjByActivator();
    }
     /// <summary>
    /// 通过反射用Activator静态生成对象
    /// </summary>
    private void CreatObjByActivator()
    {
        Type type = reflectionTest.GetType();
        object[] objects = {"张三","阿姆斯特朗回旋炮", "22cm"};
        object obj = Activator.CreateInstance(type, objects);
        //调用打印方法,看是否有输出
        ((ReflectionTest)obj).ShowContent();
    }

🌵执行结果如下

❓❓到这里有的C友肯定要说,不懂就问,什么是阿姆斯特朗回旋炮啊?❓❓

就是这货

7).通过反射,创建对象,给字段,属性赋值,调用方法

最后我们再来生成对象并修改相应的内容吧

private void Start()
    {
         CreatAndSet();
    }
     /// <summary>
    /// 通过反射,创建对象,给字段,属性赋值,调用方法
    /// </summary>
    private void CreatAndSet()
    {
        Type type = reflectionTest.GetType();
        //创建对象
        object obj = Activator.CreateInstance(type);
        //通过名字获取字段
        FieldInfo fieldInfo = type.GetField("ranking");
        //给字段赋值
        fieldInfo.SetValue(obj,1);
        //获取所有属性的信息
        PropertyInfo[] propertyInfos = type.GetProperties();
        string[] strings ={"李四", "阿姆斯特朗回旋炮", "33cm"};
        //依次给属性属性赋值
        for (int i = 0; i < propertyInfos.Length; i++)
        {
            propertyInfos[i].SetValue(obj,strings[i],null);
        }
        //根据名字找到方法的信息
        MethodInfo methodInfo = type.GetMethod("StartMove");
        //执行方法
        methodInfo.Invoke(obj, null);
        //根据名字找到方法的信息
        MethodInfo methodInfo2 = type.GetMethod("ShowRanking");
        //执行方法
        methodInfo2.Invoke(obj, null);
    }

🌵执行结果如下

三、源码

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

/// <summary>
/// 反射的相关测试
/// </summary>
public class FindOfReflection : MonoBehaviour
{
    private ReflectionTest reflectionTest;

    private void Awake()
    {
        reflectionTest = new ReflectionTest();
    }

    private void Start()
    {
        SeeConstructor();
        SeeProperty();
        SeePublicMethod();
        SeePublicField();
        CreatObjectByConstruct();
        CreatObjByActivator();
        CreatAndSet();
    }

    /// <summary>
    /// 获取构造函数的所有参数及参数的数据类型
    /// </summary>
    private void SeeConstructor()
    {
        //获取reflectionTest的Type
        Type type = reflectionTest.GetType();
        //通过Type获取这个类的所有构造函数信息
        ConstructorInfo[] constructorArray = type.GetConstructors();
        foreach (ConstructorInfo constructorInfo in constructorArray)
        {
            //获取每个构造函数的所有参数
            ParameterInfo[] parameterArray = constructorInfo.GetParameters();
            foreach (ParameterInfo parameterInfo in parameterArray)
            {
                Debug.Log("数据类型:" + parameterInfo.ParameterType.ToString() + "\\n" + "参数名字:" + parameterInfo.Name);
            }
        }
    }

    /// <summary>
    /// 通过反射获取属性
    /// </summary>
    private void SeeProperty()
    {
        //获取reflectionTest的Type
        Type type = reflectionTest.GetType();
        //获取所有属性信息
        PropertyInfo[] propertyInfos = type.GetProperties();
        foreach (PropertyInfo propertyInfo in propertyInfos)
        {
            //打印出来属性的名字
            Debug.Log("属性:" + propertyInfo.Name);
        }
    }

    /// <summary>
    /// 查看类中的公开方法
    /// </summary>
    private void SeePublicMethod()
    {
        Type type = reflectionTest.GetType();
        //通过type获取所有公开方法的信息
        MethodInfo[] methodInfos = type.GetMethods();
        foreach (MethodInfo methodInfo in methodInfos)
        {
            Debug.Log("公开方法的返回类型:" + methodInfo.ReturnType + "---" + "方法的名字:" + methodInfo.Name);
        }
    }

    /// <summary>
    /// 查看类中的公开字段
    /// </summary>
    private void SeePublicField()
    {
        Type type = reflectionTest.GetType();
        //通过type获取所有公开的字段的信息
        FieldInfo[] fieldInfos = type.GetFields();
        foreach (FieldInfo fieldInfo in fieldInfos)
        {
            Debug.Log("公开的字段的名字:" + fieldInfo.Name);
        }
    }


    /// <summary>
    /// 通过反射用构造函数动态生成对象
    /// </summary>
    private void CreatObjectByConstruct()
    {
        Type type = reflectionTest.GetType();
        Type[] typeArray = {typeof(string), typeof(string), typeof(string)};
        //根据构造函数参数类型来获取构造函数
        ConstructorInfo constructorInfo = type.GetConstructor(typeArray);
        //要传入的参数
        object[] objectArray = {以上是关于Unity C# 游戏开发 反射 Reflection 案例讲解(图文详细,带源码)的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D日常开发Unity3D中 C#反射Reflection的使用

Unity游戏开发C#基础认识与了解

C#中的反射和特性

C#探索之路:反射和特性

C#中的反射和特性

Unity游戏开发 | 浅谈Lua和C#中的闭包