【Unity学习笔记】反射

news2024/12/28 4:31:26

在这里插入图片描述


文章目录

  • 前言
  • 反射
    • 通过反射获取类型
  • Unity中的反射
  • 用反射在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\路径下

执行结果:

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

导出后的结果也是一样的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1808095.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【会议征稿,IEEE出版】第三届能源与电力系统国际学术会议 (ICEEPS 2024,7月14-16)

如今,全球能源行业正面临着前所未有的挑战。一方面,加快向清洁、可再生能源转型是遏制能源环境污染问题的最佳途径之一;另一方面,电力系统中新能源发电、人工智能技术、电力电子装备等被广泛应用和期待,以提高能源可持…

汇编:结构体

在32位汇编中,结构体(structures)用于组织和管理复杂的数据类型,结构体可以包含多个不同类型的数据项(成员);在MASM(Microsoft Macro Assembler)中,使用结构体…

Qt——升级系列(Level Four):控件概述、QWidget 核心属性、按钮类控件

目录 控件概述 QWidget 核心属性 核心属性概览 enabled geometry windowTitle windowIcon windowOpacity cursor font toolTip focusPolicy styleSheet 按钮类控件 Push Button Radio Buttion Check Box Tool Button 控件概述 Widget 是 Qt 中的核⼼概念. 英⽂原义是 "…

10.结构体、共用体、枚举

头文件&#xff1a;#include<string.h> //struct&#xff1a;结构体关键字 //stu&#xff1a;结构体类型名&#xff0c;指定了一个结构体类型&#xff0c;它相当于一个模型&#xff0c;但其中并无具体数据&#xff0c;系统对之也不分配实际内存单元//使用结构体类型必须是…

CDR2024软件破解Keygen激活工具2024最新版

CorelDRAW Graphics Suite2024最新版&#xff0c;这是一款让我爱不释手的图形设计神器&#xff01;作为一个软件评测专家&#xff0c;我一直在寻找一款能够提升我的设计效率和创造力的工具。而这款软件&#xff0c;简直就是为我量身定制的&#xff01;&#x1f389; 「CorelDR…

北航第五次数据结构与程序设计编程题复习

北航第五次数据结构与程序设计编程题复习 树叶节点遍历&#xff08;树-基础题&#xff09;计算器&#xff08;表达式计算-表达式树实现&#xff09;服务优化词频统计&#xff08;树实现&#xff09; 树叶节点遍历&#xff08;树-基础题&#xff09; 【问题描述】 从标准输入中…

OpenCV学习(4.9) OpenCV中的轮廓

1.目标 了解轮廓是什么。学习寻找轮廓&#xff0c;绘制轮廓等您将看到以下功能&#xff1a;**cv.findContours()** &#xff0c;**cv.drawContours()* 2.什么是轮廓 轮廓可以简单地解释为连接具有相同颜色或强度的所有连续点(沿边界)的曲线。轮廓是用于形状分析以及对象检测…

嵌入式学习——Linux高级编程复习(互斥锁、信号量、管道、信号)——day41

1. 同步和异步 1.1 同步 多个任务在某一时刻,先后执行顺序可以被确定 同步操作要求一系列操作严格按照顺序执行&#xff0c;一个操作只有在前一个操作完成之后才能开始。在计算机编程中&#xff0c;这意味着当一个程序或线程发出一个请求或调用后&#xff0c;它会暂停执行&…

java自动化之java基础03-09java基础之数组

数组 1、定义 数组是一种用于存储固定大小的同类型数据的数据结构 1&#xff09;固定大小 2&#xff09;同类型数据的存储 2、声明数组 1&#xff09;数据类型[] 变量名称&#xff1b; 例如&#xff1a;int[] numsArry; 2&#xff09;数据类型 变量名称[]; 例如&#xf…

27.机会成本

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/677 题目描述 明天有 𝑛n 门考试,今晚只…

【C++修行之道】类和对象(五)日期类的实现、const成员、取地址及const和取地址操作符重载

目录 一、 日期类的实现 Date.h 1.1 GetMonthDay函数&#xff08;获取某年某月的天数&#xff09; 问&#xff1a;这个函数为什么不和其他的函数一样放在Date.cpp文件中实现呢&#xff1f; 1.2 CheckDate函数&#xff08;检查日期有效性&#xff09;、Print函数&#xff08;…

计算机毕业设计 | SpringBoot宠物医院管理 宠物商城购物系统(附源码)

写在前面 Le Dao宠物医院管理系统是一个超大型的&#xff0c;完成度很高的&#xff0c;集宠物医疗、宠物美容、宠物交易、宠物周边等各种功能于一身的&#xff0c;权限涵盖普通用户、医生、化验师、美容师、仓库主管、采购员等多种角色于一体的大型宠物医疗&#xff0c;购物系…

Java 数据类型 -- Java 语言的 8 种基本数据类型、字符串与数组

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 004 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

1035 插入与归并(测试点6)

solution 类型判断&#xff1a;插入排序中已排序的部分有序&#xff0c;未排序的和原数组元素相同&#xff1b;否则为归并排序测试点6&#xff1a;对于归并排序的子序列长度&#xff0c;不能简单视为前k个有序则子序列长度就是k 例如该测试用例的归并排序的子序列长度应该为2&…

重新认识Word —— 制作简历

重新认识Word —— 制作简历 PPT的图形减除功能word中的设置调整页边距进行排版表格使用 我们之前把word长排版文本梳理了一遍&#xff0c;其实word还有另外的功能&#xff0c;比如说——制作简历。 在这之前&#xff0c;我们先讲一个小技巧&#xff1a; PPT的图形减除功能 …

记录一次被谷歌封号后又解封的过程

先提前恭祝2024年所有参加高考的学子们都能金榜题名&#xff0c;会的全对&#xff0c;不会的蒙的全对&#xff01; 一、背景 众所周知&#xff0c;谷歌、ios应用市场对app的审查都是极其严格的&#xff0c;开发者稍有不慎就会被谷歌下架应用&#xff0c;乃至封号。我们公司是做…

目标检测应用场景—数据集【NO.36】甘蔗叶片病害识别数据集

写在前面&#xff1a;数据集对应应用场景&#xff0c;不同的应用场景有不同的检测难点以及对应改进方法&#xff0c;本系列整理汇总领域内的数据集&#xff0c;方便大家下载数据集&#xff0c;若无法下载可关注后私信领取。关注免费领取整理好的数据集资料&#xff01;今天分享…

error while loading shared libraries 找不到动态库问题如何解决

在使用 c 或 c 开发应用时&#xff0c;在启动程序时&#xff0c;有时会遇到这个错误&#xff0c;找不到动态库。这个时候&#xff0c;我们使用 ldd 来查看&#xff0c;发现可执行文件依赖的动态库显示为 not found。 1 实验代码 使用如下 3 个文件做实验。 hello.h 中声明了函…

Mysql使用中的性能优化——搭建Mysql的监测服务

大纲 环境安装配置Mysql安装设置root密码新增远程访问账户修改绑定地址重启 新增 MySQL Server Exporter 用户 安装启动mysqld_exporter安装启动新增配置启动直接启动以Service形式启动 安装启动Prometheus创建用户下载并解压修改配置启动 安装启动grafana安装启动 测试参考资料…

地图商家数据怎么查看?揭秘采集软件工作原理!

地图商家数据怎么查看&#xff1f;其实主要就是两种方法&#xff1a; 1. 直接使用地图服务提供的API&#xff1a;大多数地图提供商&#xff08;如Google地图&#xff0c;百度地图等&#xff09;都会提供一些API&#xff0c;通过这些API&#xff0c;可以获取到它们所拥有的商家…