[英]Faster calling of methods using reflection
我正在將一些舊代碼從 AS3(通過 Haxe)移植到 C#。
部分代碼已轉譯,其他部分我已在 C# 中手動重寫。其中一部分是事件調度。
我有事件偵聽器注冊到事件調度程序,所有偵聽器都有這樣的簽名:
public void handleSomething(Event e)
// they may also use a subclass of Event as a parameter
public void handleAnother(MouseEvent e)
事件保留少量數據和類型:
public class Event {
public const string ENTER_FRAME = "enter_frame";
public const string RESIZE = "resize";
public const string CHANGE = "change";
readonly string type;
public Event(string type) {
this.type = type;
}
}
我保留了一個以特定事件類型為鍵的列表(一個字符串,由於遺留原因),一旦事件被分派,我就會找到以該字符串為鍵的適當處理程序,並使用事件數據調用它們。
我目前正在使用反射來執行此操作,但事實證明它非常慢。 我發現了幾個共享此問題的線程。
我的特殊問題是方法簽名會有所不同,如果它始終是一個Event
作為參數我可以使用提供的解決方案,但是唉。
我可以在設置時交易一些內存/時間以使后續調用更快。 我可以獲得對該方法的引用並計算出它期望的類型,但我不確定以后如何存儲和調用它?
您可以為每個處理程序方法創建和編譯 LINQ 表達式並將其緩存以備將來使用。
public class CompiledDelegate
{
// Assume that there is one one method per handler class type, add method name to dictionary key if necessary
private static Dictionary<Type, CompiledDelegate> _Cache = new Dictionary<Type, CompiledDelegate>();
public static CompiledDelegate Get(Type handlerType, string methodName)
{
CompiledDelegate result;
if (!_Cache.TryGetValue(handlerType, out result))
{
var method = handlerType.GetMethod(methodName);
// determine type of single method parameter
var paramType = method.GetParameters().Single().ParameterType;
// create expression tree (object h, object p) => ((handlerType)h).MethodName((paramType)p)
var exprHandler = Expression.Parameter(typeof(object), "h");
var exprParam = Expression.Parameter(typeof(object), "p");
var lambda = Expression.Lambda(
Expression.Call(
Expression.TypeAs(exprHandler, handlerType), // instance, cast object to handlerType
method, // method
Expression.TypeAs(exprParam, paramType) // parameter, cast object to paramType
),
exprHandler, exprParam // lamda params
);
result = new CompiledDelegate()
{
Method = method,
// compile expression
Compiled = (Action<object, object>)lambda.Compile()
};
_Cache.Add(handlerType, result);
}
return result;
}
public MethodInfo Method { get; private set; }
public Action<object, object> Compiled { get; set; }
}
一旦你有了 hander 實例,你就可以通過編譯委托調用它的方法:
CompiledDelegate.Get(handler.GetType(), "handlerSomething").Compiled(handler, mouseEvent)
您可以為每個處理程序預先生成 CompiledDelegate,並與處理程序本身一起添加到調度表中。
通過編譯委托調用方法(當然是一旦編譯)比通過反射調用相同方法快大約 10 倍。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.