int main() {
Test t;
auto memberFunc = t.GetFuncPointer();
// 调用获取到的私有函数指针
(t.*memberFunc)();
return 0;
}
运行这个代码,你可以看到输出了Hello world!如果不熟悉函数指针的话,可以再去学习一下基础。
可以看到通过一些魔法,我们成功调用到了本来不可能访问的函数,并且这个函数也无法找到正常途径下的任何调用引用(IDE上查引用是查不到的)。
而C#则直接内置了这样一套机制,编译器直接生成了这些东西,并最终构建到你的程序中,并且不仅仅是调用函数,可以操作和访问的东西要多得多。
例如官方示例里面有这样一段代码:
// Using GetType to obtain type information:
int i = 42;
Type type = i.GetType();
Console.WriteLine(type);
对于任何C#的类型,包括内置的类型int之类的,都可以通过GetType()拿到这个类型的信息,而通过Type类,则可以获取到这个类型代码定义的各种东西,包括有哪些函数,哪些成员,然后还能调用函数。
那么到了Unity中,Unity则是通过在游戏运行开始的时候,将GameObject所持有的组件,或者是我们写的MonoBehaviour类收集起来,然后通过反射,获取到我们所有写在代码里面所关心的回调函数,然后在对应时机,使用组件类的实例+反射得到的函数信息来调用你所写的逻辑。
如果实际实现一下Unity做法就是类似这样:
// 从GameObject中拿到每个组件,其中就有我们的DemoTest类
Monobehaviour behaviour = demoTest;
// 反射得到我们写的DemoTest的类型信息
Type type = behaviour.GetType();
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DemoTest : MonoBehaviour
{
public int testValue1;
[SerializeField]
private int testValue2;
// Start is called before the first frame update
void Start()
{
Debug.Log("Hello World!");
}
// Update is called once per frame
void Update()
{
}
}
改完让Unity自动编译后,可以再次选中Cube观察Inspector面板来看:
可以看到我们的两个变量都上去了,并且Unity还帮我们做了显示名称的优化。
但是值得注意的是,并不是所有类型的数据都可以支持在编辑器上显示,为了支持显示,数据类型必须是可序列化的,Unity默认支持了很多类型的序列化操作,但是对于我们自定义的类则默认不支持,如果想要Unity支持,则需要对对应的类的定义加上可序列化的属性:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DemoTest : MonoBehaviour
{
public int testValue1;
[SerializeField]
private int testValue2;
[System.Serializable] // <-- 这一行是关键,必须有这个属性,否则Unity是无法识别这个类型数据的
public class CustomDataType
{
public int nestValue;
}
public CustomDataType testValue3;
// Start is called before the first frame update
void Start()
{
Debug.Log(&#34;Hello World!&#34;);
}
// Update is called once per frame
void Update()
{