我需要調用泛型類的實例方法。簽名看起來像這樣:使用表達式的C#加速方法調用泛型類
public class HandlerFactory
{
public static IHandler<T> Create<T>();
}
public interface IHandler<T>
{
T Read(Stream s);
void Write(Stream s, T v);
}
我設法通過使用表達式和DynamicInvoke得到它的工作。可悲的是DynamicInvoke的表現並不好。我不能將代理強制轉換爲Action<MemoryStream, T>
,因爲我不知道編譯時的類型。
public class Test
{
public static void Write(MemoryStream s, object value)
{
var del = GetWriteDelegateForType(value.GetType());
// TODO: How to make this faster?
del.DynamicInvoke(s, value);
}
private static object GetHandlerForType(Type type)
{
var expr = Expression.Call(typeof(HandlerFactory), "Create", new[] { type });
var createInstanceLambda = Expression.Lambda<Func<object>>(expr).Compile();
return createInstanceLambda();
}
private static Delegate GetWriteDelegateForType(Type type)
{
var handlerObj = GetHandlerForType(type);
var methodInfo = handlerObj.GetType().GetMethod("Write", new[] { typeof(MemoryStream), type });
var arg1 = Expression.Parameter(typeof(MemoryStream), "s");
var arg2 = Expression.Parameter(type, "v");
var handlerObjConstant = Expression.Constant(handlerObj);
var methodCall = Expression.Call(handlerObjConstant, methodInfo, arg1, arg2);
var lambda = Expression.Lambda(methodCall, arg1, arg2);
return lambda.Compile();
}
}
請注意,我沒有基準lambda代,只是調用DynamicInvoke。
有什麼方法可以用更快的東西來代替DynamicInvoke嗎?
更新:我評估了3個答案,其中包含代碼示例,並選擇與Lasse V. Karlsen答案一起歸因於簡單性。 (上Grax的代碼注:儘管緩存MakeGenericMethod調用它似乎比在委託包裝調用方法要慢)
Method | Median | StdDev |
------------------- |-------------- |----------- |
MyLambda | 1,133.2459 ns | 25.1972 ns |
ExplicitCall | 0.6450 ns | 0.0256 ns |
Test2DelegateLasse | 10.6032 ns | 0.2141 ns |
LambdaGroo | 10.7274 ns | 0.1099 ns |
InvokeGrax | 349.9428 ns | 14.6841 ns |
你可以創建一個人們可以修補的[mcve]嗎?一個代表一組特定的現有代碼,以便我可以在我的計算機上運行它以獲得基線,然後修改它以查看是否可以更快地實現它? –
擁有插件工廠的通用接口並不合理,恕我直言。 – Groo
這是一個第三方庫,所以我不能決定它是否有意義。以下是演示性能的完整示例:http://pastebin.com/K3q4dgMk。我的電腦上的820ms到2ms比較直接方法調用和DynamicInvoke。 – coalmee