C#反射——掀起Unity Editor面纱

Author Avatar
Kanglai Qian 3月 20, 2017

之前在群里看到有人提到Profiler Memory Plus这个插件,相当不错~在原来Profiler功能上扩展出了diff功能 非常实用。

然后我就在想这个是怎么做的呢,某天在折腾shader keyword的时候突然灵光一闪,莫非是private API搞的? 动手试了下果然可行。

具体解释一下:Unity引擎底层是用C++写的,但是外围逻辑绝大部分都是C#实现,包括Editor本身。平常我们常见的UnityEngine.dll和UnityEditor.dll里就有大量的宝藏值得挖掘,网上已经有提供了一份UnityDecompiled(当然也可以自己用ILSpy等工具处理)。我个人觉得可以分为两类:

  • Undocument API 在代码里可以直接调用,但是并没有在文档里出现
  • Private API 无法在代码里直接调用,一般是internal class或者private作用域

但是谁让这些代码是人见人爱的C#代码呢!在编辑器下完全可以使用反射来绕开这个限制。具体来说举个例子,如果我们希望访问到ProfilerWindow里的某个私有变量m_ProfilerWindow

private static List<ProfilerWindow> m_ProfilerWindows = new List<ProfilerWindow>();

完全可以这么写

m_ProfilerWindows = tProfilerWindow.GetField("m_ProfilerWindows", BindingFlags.NonPublic | BindingFlags.Static);
IList windows = m_ProfilerWindows.GetValue(null) as IList;

这样直接绕开了internal和private双重限制。在这个思路下,三下五除二就自己实现了想要的功能

最后也不得不提示下这样做的缺点:

  • 反射在性能上还是有不少损失的
  • 如果Unity升级导致变量名变动等,就会代码出错需要人肉维护…

不过总得来说,作为编辑器扩展非常靠谱,最近用这个思路还折腾了不少事情,譬如设置Material Inspector面板的Reflection Probe/完美抓取shader keyword等。这酸爽感觉就是打开了一个新世界的大门(逃