Unity[C#] Reflection Use

 

Reflection

Reflection是C#程序员的一个最有力工具

最常用的例子来说明反射的用处是一个插件系统。假设你正在创建一个 接受用户创建 的扩展程序,有没有办法预先知道哪些方法这个扩展他们有或有扩展的名字将是什么,除非你可以检查编译的程序集,并在运行时提取信息,这正是反射呢,等等

功能需求

目前,我正在使用Unity开发一个游戏,用户界面是在游戏中(3D UI)。这意味着我会使用Unity提供的API,它提供了相当强大的工具集来创建交互式图形用户界面的。

场景中的3D对象可以响应用户的输入。Unity让你检测鼠标事件,但没有办法用模块化的方法编写单个事件处理程序?

为了得到这个功能,我不得不扩展Unity的Editor和Inspecot 来暴露我的代码,这听起来很复杂,但这些定位方法,并随后调用它们的底层代码很简单。

interface2

实现思路及方法

1. 暴露你需要的方法

之前,我们接触过C#的Reflection API,我们需要创建一个新的属性

Attributes allow us to assign metadata to classes, methods, properties, etc. that can be read back by reflection.

属性允许我们指定方法,类属性等等,可以通过反射来读到这些值。

In this case, our attribute is going to be called “ExposeToEditor” and we're going to use it to tag instance methods (and classes with static methods) that Unity's editor should recognise as valid event handlers.

在这种情况下,我们的属性将被称为:ExposeEditor ,我们打算用它来标记Instance(和类的静态方法)Unity的Editor可以识别出它们是有效的事件处理程序

因此,我们创建了一个新的脚本文件,并确保 using Systm;,然后我们编写以下代码:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class ExposeToEditor : Attribute { }

这将创建一个标准属性系统,我们现在可以分配给任何方法或类,例如:

[ExposeToEditor]
 public void OnThisButtonClick(object sender) { };

现在,我们可以放在一起,将跟踪标识以这种方式方法的代码

2. 定位我们的Public的方法

inunity

点击上面的图像,将其展开,并期待在最右边的面板中-你会看到一个名为:Interface Click Handler的脚本。这是一个Editor的界面,我们编码,可以让我选择包含我所需要的脚本和方法的特定对象。此图片是更提供上下文是什么,我来解释,而不是使用Reflection的重要组成部分。因此,如果它没有多大,不用担心。

最重要的是这些背后的编辑器界面,它需要定位的方法在脚本的逻辑,下面是关键的部分

var type = t.OnClickMonoBehaviour.GetType(); List<string> methodNames =new List<string>(); List<MethodInfo> methods =new List<MethodInfo>(type.GetMethods()); foreach (MethodInfo mi in methods) { if (mi.IsDefined(typeof(ExposeToEditor), true)) { methods.Add(mi); methodNames.Add(mi.Name); } }

让我们把它分解,我们要做的第一件事情就是,获取选定的脚本类型,后者被存储 在 OnClickMonoBehaviour 对象的属性t。然后我们实例化一些List来存储这些方法的信息,foreach 循环遍历获取所有的包含在这个Script Type的public方法,通过type.GetMethods;

.GetMethods为我们提供一个数组的MethodInfo对象,.MethodInfo包含了大量的关于每个方法的信息,我们可以使用甚至该方法MethofInfo.Invoke.然而,这并不是最有效的方式来动态调用一个方法,以后的东西我会介绍。

现在,我们不希望来存储所有的方法,我们只是想通过那些我们先前创建的属性暴露出来,因此,我们使用MethofInfo.IsDefind() 方法来检查是否 ExposeToEditor 连接到该方法。要彻底,我们告诉 IsDefind 检查继承的类型也是如此。

一旦循环完成之后,我们将不得不包含的方法作为字符串不只是名字,但是这些方法本身,在形式列表 MethofInfo 对象。的字符串列表是用来填充的最后一个影像的”关于Click 方法” 下拉列表中,这样我们就可以很容易地选择正是我们所需要的。

3. 存储和动态调用方法

用方法名存储,所有我们现在需要做的是理清了“Click” 的逻辑,这是用来在游戏中,正如我们前面提到的,要做到这一点最简单的方式是通过使用MethodInfo的动态调用。例如:

MethodInfo mi = VariableContainingMethodInfo;
mi.Invoke();

并没有什么真的错了,这干得不错,但是,我们可以执行通过使用  Action<T> Delegate 并缓存它

首先,我们在某处定义缓存变量

private Action<object> CacheAction;

然后,当界面元件由玩家互动,我们缓存的方法,并用它在随后的相互作用。

CachedAction = (Action<object>)Delegate.CreateDelegate(typeof(Action<object>),OnClickMonoBehaviour,OnClickMethod);

现在,有几个重载 Delegate.CretaeDelegate ,在这种情况下 OnClickMonoBehaviour 和 OnClickMethod 都是字符串。委托创建并存储在CacheAction ,所以当我们要调用它,我们只是这样做:

CacheAction(object);

在这儿 object 只是一个灵活的参数,我们可以根据需要将信息传递到事件处理程序。

The best way to get more familiar with it is to check it out on MSDN. For more practical examples, Stack Exchange is a valuable resource, providing specific examples of how to get reflection doing what you want it to.

posted @ 2014-07-16 11:48  赵青青  阅读(2022)  评论(0编辑  收藏  举报