簡體   English   中英

使用反射更快地調用方法

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM