【Unity学习笔记】反射

在这里插入图片描述



前言

在我平时做项目的时候,由于我们做的项目都是很简单的,所以不怎么接触反射机制。最早了解反射机制是关于Invoke的时候,知道可以通过方法名来直接进行Invoke调用,但是由于反射调用存在性能开销较大的问题,因此就没打算深入了解

不过反射作为C#的高级特性,可以不用,但是不能不了解

反射(Reflection) 的含义和用法

反射

反射是.NET中的重要机制,通过反射可以得到*.exe或*.dll等程序集内部的接口、类、方法、字段、属性、特性等信息,还可以动态创建出类型实例并执行其中的方法。
反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。
可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。

简单来说,反射能实现的功能极其强大,可以直接通过读取exe或者dll程序集获取其中的接口、类、方法、字段、属性、特性等信息。

通过反射获取类型

反射获取类型的方式有三种:

  1. 通过typeof获取某个值的类型
Type personType=typeof(Person);

2.通过一个对象获取该对象所对应的类的类型

Type=Person.GetType();

3.通过类的名称字符串获取对应的类型

Type strType =Type.GetType("Person");

注意,上述说的三种方法不止包括获取class,只需要换成对应的方法就能获取接口、方法、字段、属性、特性等等信息。这意味这只要使用反射就可以获取代码中的几乎任何信息。甚至私有的变量成员和方法都能获取

反射(Reflection) 的含义和用法

只需查看上文就可以知道反射的功能有多全面,返回所需的类型的信息,根据访问修饰符获取类型成员信息,通过反射直接构造实例化对象,通过反射获取类中的所有属性,字段,事件,方法,构造函数等等。私有的都可以随便访问。

优点:

  • 反射提高了程序的灵活性和扩展性。
  • 降低耦合性,提高自适应能力。
  • 它允许程序创建和控制任何类的对象,无需提前硬编码目标类。

缺点:

  1. 性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
  2. 使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。

实际上反射的优点也是它的缺点。为什么我们不用反射来解耦,不用反射做拓展呢?除了反射本身调用时需要查找解释造成过高的性能开销之外,反射本身绕过了程序内部逻辑,可读性太差了。如果我们要使用反射调用函数,不还是需要知道函数方法实现了什么吗?而解耦这一目的完全可以从设计模式上来解决。

Unity中的反射

反射在Unity中实现的功能主要是:

  • 使用反射,我们可以动态的访问代码中的成员,或是进行动态实例化。例如我们想要实现游戏中的控制台Debug功能,让用户可以使用简单的指令就能创建一些游戏实例,例如用户可以用指令add ObjName 100来为场景中增加100个对应名称的游戏物体实例,我们就可以用反射机制,获取ObjName字符串对应的Type并生成物体:
Type type = typeof(ObjName);
object instance = Activator.CreateInstance(type);
  • 另一种想法是,使用反射,我们可以实现一些热更新的功能。例如对于若要生成一个物体,我们可以把它封装在dll程序集中,并通过反射机制,用物体的名称来直接实例化dll中的该物体。而如果此时客户端要实现不停机热更新该物体的数值,只需下载替换dll文件即可,因为物体名称并没变,我们通过反射机制获取直接获取更新的成员并更新数值。

合理使用反射机制,可以简单的实现一些麻烦的功能,而且将程序集之间进行分离,也有助于减少程序的耦合性。


用反射在Unity中动态加载

想要在unity中创建并加载程序集,我们需要在文件夹内生成一个Assembly Definition

在这里插入图片描述
在这里插入图片描述
我们会发现创建了一个拼图icon的文件,这个文件就是我们的程序集,但它目前是未编译的状态,格式是asmdef,只有在被导出后才会被编译为dll

官方文档——程序集定义
Unity程序集定义(Assembly Definition File)功能详解

我们在与它同目录下所创建的脚本都会被编译到这个程序集中
在这里插入图片描述

在面板中可以查看它的属性,首先程序集的名称是在面板上的Name定义的,而不是该文件本身的名称

这里显示了三个选项(高版本还有其他选项),AutoReferenced代表了该程序集会自动引用其他程序集,导致其他程序集更新后该程序集也被自动重编译,如果我们不希望这个程序集在其他程序集更新后被重编译,就关闭它

override References代表了我们指定该程序集会引用哪些程序集,并在Assembly Definition References里选择添加对应的Dll

最下面的面板Platforms约定在导出到哪些平台时该程序集会被编译

Define Constraints代表了该程序集会在哪些宏被定义的时候被编译,只有当代码中使用了指定宏时才会使用该程序集。例如我下面的代码:

using System.IO;
using System.Reflection;
using UnityEngine;

public class TestClass : MonoBehaviour
{
	private string _localPath;

	private void Start()
	{

#if UNITY_EDITOR
		// 我不知道如何在项目中直接加载未编译的程序集,只能导出后加载了
		_localPath = Path.Combine(Path.GetDirectoryName(Application.dataPath),"Apps");
		string[] DataFloder = Directory.GetDirectories(_localPath, "*_Data");
		_localPath = Path.Combine(DataFloder[0], "Managed", "Test.dll");
#else
		LocalPath = Path.Combine(Application.dataPath, "Managed", "Test.dll");
#endif
		// 可笑的是程序集只能加载不能卸载,导致程序关闭后程序集依然被访问
		Assembly _assembly = Assembly.LoadFrom(_localPath);
		var t = _assembly.GetType("TestReflect");
		gameObject.AddComponent(t);
	}
}

public class TestReflect : MonoBehaviour
{
    void Start()
    {
        Debug.Log("反射成功调用");
    }
}

由于我定义了!UNITY_EDITOR,也就是非编辑器中被编译,经测试,导出时会正常编译dll,然后在编辑器状态,代码是正常执行的。

但是如果定义的是UNITY_EDITOR,则导出时不会编译为Dll,猜想是由于导出时的bulidPipeline使用了!UNITY_EDITOR宏,因此若定义了!UNITY_EDITOR的引用约束,则导出时会编译。

当然我们还可以定义其他的编译引用约束,根据具体使用情况来判断

导出后的Dll路径在GameScence_Data\Managed\路径下

执行结果:

在这里插入图片描述
在这里插入图片描述

导出后的结果也是一样的

  • 22
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习Unity3D时,以下是一些重要的笔记: 1. Unity3D基础知识: - 游戏对象(Game Objects)和组件(Components):了解游戏对象的层次结构和组件的作用。 - 场景(Scenes)和摄像机(Cameras):学会如何创建场景并设置摄像机视角。 - 材质(Materials)和纹理(Textures):掌握如何创建和应用材质和纹理。 - 动画(Animations):学习如何创建和控制游戏对象的动画。 2. 脚本编程: - C#语言基础:了解C#语言的基本语法和面向对象编程概念。 - Unity脚本编写:学习如何编写脚本来控制游戏对象的行为和交互。 - 常见组件和功能:掌握常见的Unity组件和功能,如碰撞器(Colliders)、刚体(Rigidbodies)、触发器(Triggers)等。 3. 游戏开发流程: - 设计游戏关卡:了解如何设计游戏场景和关卡,包括布局、道具、敌人等。 - 游戏逻辑实现:将游戏规则和玩家交互转化为代码实现。 - UI界面设计:学习如何设计游戏中的用户界面,包括菜单、计分板等。 - 游戏优化和调试:优化游戏性能,解决常见的错误和问题。 4. 学习资源: - Unity官方文档和教程:官方提供了大量的文档和教程,逐步引导你学习Unity3D。 - 在线教程和视频教程:网上有很多免费和付费的Unity教程和视频教程,可根据自己的需求选择学习。 - 社区论坛和博客:加入Unity开发者社区,与其他开发者交流并获取帮助。 通过系统地学习这些内容,你将能够掌握Unity3D的基础知识并开始开发自己的游戏项目。记得不断实践和尝试,不断提升自己的技能!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值