如何通过反射调用内部静态函数
我们用ILSpy反编译UnityEditor.dll,假设现在我们想要调用UnityEditor.EditorGUIUtility的这个DrawHorizontalSplitter方法,因为它是internal的,科普:
internal(内部)关键字是类型和类型的成员访问修饰符。只有在同一程序集中可访问,可以跨类。
注:ILspy是一个开源的.net反编译软件,使用十分方便,下载地址:https://github.com/icsharpcode/ILSpy/releases
所以我们就无法在外部直接调用DrawHorizontalSplitter这个方法。
但是,我们可以用反射的方式来调用。
我们封装一个反射工具的类:
using UnityEngine;
using System;
using System.Reflection;
public class ReflectionTools
{
public static void Call(string typeName, string methodName, params object[] args)
{
Call<object>(typeName, methodName, args);
}
public static T Call<T>(string typeName, string methodName, params object[] args)
{
Type type = Type.GetType(typeName);
T defaultValue = default(T);
if(null == type) return defaultValue;
Type[] argTypes = new Type[args.Length];
for(int i=0, count = args.Length; i< count; ++i)
{
argTypes[i] = null != args[i] ? args[i].GetType() : null;
}
MethodInfo method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, argTypes, null);
if(null == method)
{
Debug.LogError(string.Format("method {0} does not exist!",methodName));
return defaultValue;
}
object result = method.Invoke(null, args);
if(null == result)
return defaultValue;
if(!(result is T))
{
Debug.LogError(string.Format("method {0} cast failed!",methodName));
return defaultValue;
}
return (T)result;
}
}
这样,我们就可以调用了:
ReflectionTools.Call("UnityEditor.EditorGUIUtility, UnityEditor", "DrawHorizontalSplitter", new Rect(0f,0f,100f,100f));
同理,假设我们想用EditorStyles的toolbarSearchField属性:
我们先封装工具接口
using UnityEngine;
using System;
using System.Reflection;
public class ReflectionTools
{
public static T GetProperty<T>(string typeName, string propertyName)
{
return GetProperty<T>(null, typeName, propertyName);
}
public static T GetProperty<T>(object instance, string typeName, string propertyName)
{
bool isStatic = null == instance;
Type type = Type.GetType(typeName);
T defaultValue = default(T);
if(null == type) return defaultValue;
BindingFlags flag = (isStatic ? BindingFlags.Static : BindingFlags.Instance);
PropertyInfo property = type.GetProperty(propertyName, flag | BindingFlags.Public | BindingFlags.NonPublic);
if(null == property)
{
Debug.LogError(string.Format("property {0} does not exist!",propertyName));
return defaultValue;
}
object result = property.GetValue(instance, null);
if(null == result)
return defaultValue;
if(!(result is T))
{
Debug.LogError(string.Format("property {0} cast failed!",propertyName));
return defaultValue;
}
return (T)result;
}
}
调用:
GUIStyle style = ReflectionTools.GetProperty<GUIStyle>("UnityEditor.EditorStyles, UnityEditor", "toolbarSearchField");
如果要获取成员变量,可以封装一个GetField方法,原理和GetProperty类似,只需要把type.GetProperty缓存type.GetField即可:
using UnityEngine;
using System;
using System.Reflection;
public class ReflectionTools
{
public static T GetField<T>(string typeName, string fieldName)
{
return GetField<T>(null, typeName, fieldName);
}
public static T GetField<T>(object instance, string typeName, string fieldName)
{
bool isStatic = null == instance;
Type type = Type.GetType(typeName);
T defaultValue = default(T);
if(null == type) return defaultValue;
BindingFlags flag = (isStatic ? BindingFlags.Static : BindingFlags.Instance);
FieldInfo field = type.GetField(fieldName, flag | BindingFlags.Public | BindingFlags.NonPublic);
if(null == field)
{
Debug.LogError(string.Format("field {0} does not exist!",fieldName));
return defaultValue;
}
object result = field.GetValue(instance, null);
if(null == result)
return defaultValue;
if(!(result is T))
{
Debug.LogError(string.Format("field {0} cast failed!",fieldName));
return defaultValue;
}
return (T)result;
}
}