Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
加速反射调用C#/.NET_C#_.net_Reflection_Invoke - Fatal编程技术网

加速反射调用C#/.NET

加速反射调用C#/.NET,c#,.net,reflection,invoke,C#,.net,Reflection,Invoke,有很多关于加速反射调用的帖子,例如: 在这里: 我的问题是关于加速泛型调用。这可能吗 我有一个抽象类和一个实现它的类 public abstract class EncasulatedMessageHandler<T> where T : Message { public abstract void HandleMessage(T message); } public class Handler : EncasulatedMessageHandler<MyM

有很多关于加速反射调用的帖子,例如:

在这里:



我的问题是关于加速泛型调用。这可能吗

我有一个抽象类和一个实现它的类

public abstract class EncasulatedMessageHandler<T> where T : Message
{
    public abstract void HandleMessage(T message);
}

public class Handler : EncasulatedMessageHandler<MyMessageType>
{
    public int blat = 0;
    public override void HandleMessage(MyMessageType message) { blat++; }
}
公共抽象类EncasulatedMessageHandler,其中T:Message
{
公开摘要无效处理消息(T消息);
}
公共类处理程序:EncasulatedMessageHandler
{
公共int blat=0;
公共重写无效HandleMessage(MyMessageType消息){blat++;}
}
我想做的是建立这些消息处理程序类的列表,并快速调用它们的HandleMessage()


目前,我正在做的事情大致如下:

object handler = Activator.CreateInstance(typeof(Handler)); // Ignore this, this is done up front.

MethodInfo method = type.GetMethod("HandleMessage", BindingFlags.Instance | BindingFlags.Public);

Action<object> hook = new Action<object>(delegate(object message)
{
    method.Invoke(handler, new object[] { message });
});

// Then when I want to invoke it:

hook(new MyMessageType());
objecthandler=Activator.CreateInstance(typeof(handler));//忽略这一点,这是提前完成的。
MethodInfo method=type.GetMethod(“HandleMessage”,BindingFlags.Instance | BindingFlags.Public);
动作挂钩=新动作(委托(对象消息)
{
调用(处理程序,新对象[]{message});
});
//然后,当我想调用它时:
钩子(新的MyMessageType());

这不是全部,但重要的是

Invoke方法非常慢,我想保留类上的泛型参数,我意识到我可以将其锁定到对象并将其强制转换到HandleMessage方法中,但我试图避免这样做

我能做些什么来加快速度吗?目前它比直接通话慢几个数量级

任何帮助都将不胜感激。

不,这(很遗憾)是不可能的。反射很慢,MethodInfo.Invoke()也不例外。您不能使用(通用)接口,从而直接调用吗


编辑更新:我想到了一件事来真正加快这一速度,但编码开销是巨大的:您可以使用动态代码生成和编译。这意味着动态地构建调用该方法的源代码,而不进行反射,动态地编译和执行该方法。这意味着在创建和编译完成工作的类时,最初会对性能产生影响,但随后每次调用都会直接调用。

使用
Delegate.CreateDelegate()
应该快得多。您将得到一个指向实际函数的指针,而不是调用
Invoke()
的委托

试试这个:

object handler = Activator.CreateInstance(typeof(Handler)); 
var handlerType = handler.GetType();
var method = handlerType.GetMethod("HandleMessage", BindingFlags.Instance | BindingFlags.Public);
var paramType = handlerType.GetGenericArguments()[0];

// invoke the MakeHandleMessageDelegate method dynamically with paramType as the type parameter
// NB we're only doing this once
Action<object> hook = (Action<object>) this.GetType().GetMethod("MakeHandleMessageDelegate")
            .MakeGenericMethod(paramType)
            .Invoke(null, new [] { handler });
objecthandler=Activator.CreateInstance(typeof(handler));
var handlerType=handler.GetType();
var method=handlerType.GetMethod(“HandleMessage”,BindingFlags.Instance | BindingFlags.Public);
var paramType=handlerType.GetGenericArguments()[0];
//使用paramType作为类型参数动态调用MakeHandleMessageDelegate方法
//注意,我们只做一次
Action hook=(Action)this.GetType().GetMethod(“MakeHandleMessageDelegate”)
.MakeGenericMethod(paramType)
.Invoke(null,新[]{handler});
在同一类中添加以下泛型方法。我们在上面动态调用它,因为我们在编译时不知道类型参数

public static Action<object> MakeHandleMessageDelegate<T>(object target)
{
    var d = (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), target, "HandleMessage");

    // wrap the delegate another that simply casts the object parameter to the required type
    return param => d((T)param);
}
public静态操作MakeHandleMessageDelegate(对象目标)
{
vard=(Action)Delegate.CreateDelegate(typeof(Action),target,“HandleMessage”);
//将委托包装为另一个,该委托仅将对象参数强制转换为所需类型
返回参数=>d((T)参数);
}
然后有一个委托将参数强制转换为所需类型,然后调用
HandleMessage
方法。

是否使用C#4?如果是这样,
dynamic
可能会加快速度:

Action<object> hook = message => ((dynamic)handler).HandleMessage((dynamic)message);
Action hook=message=>((动态)处理程序);

您可以使用
Delegate::CreateDelegate
。这比
Invoke()
要快得多

var handler=Activator.CreateInstance(typeof(handler));
var method=type.GetMethod(“HandleMessage”,BindingFlags.Instance | BindingFlags.Public);
var hook=(Action)Delegate.CreateDelegate(typeof(Action)、处理程序、方法);
//然后,当您要调用它时:
钩子(新的MyMessageType());
可以自由地对它进行基准测试,但我以前曾让它坐过板凳,而且速度明显更快

编辑:我现在明白你的问题了,你不能按我建议的方式来做

您可以使用表达式编译为您执行调用的委托,这将非常快:

var type = typeof(Handler);
var instance = Activator.CreateInstance(type);
var method = type.GetMethod("HandleMessage", BindingFlags.Instance | BindingFlags.Public);

var originalType = type;
// Loop until we hit the type we want.
while (!(type.IsGenericType) || type.GetGenericTypeDefinition() != typeof(EncasulatedMessageHandler<>))
{
    type = type.BaseType;
    if(type == null)
        throw new ArgumentOutOfRangeException("type");
}

var messageType = type.GetGenericArguments()[0]; // MyMessageType

// Use expression to create a method we can.
var instExpr = Expression.Parameter(typeof(object), "instance");
var paramExpr = Expression.Parameter(typeof(Message), "message");
// (Handler)instance;
var instCastExpr = Expression.Convert(instExpr, originalType);
// (MyMessageType)message
var castExpr = Expression.Convert(paramExpr, messageType); 
// ((Handler)inst).HandleMessage((MyMessageType)message)
var invokeExpr = Expression.Call(instCastExpr, method, castExpr); 
// if(message is MyMessageType) ((Handler)inst).HandleMessage((MyMessageType)message);
var ifExpr = Expression.IfThen(Expression.TypeIs(paramExpr, messageType), invokeExpr);

// (inst, message) = { if(message is MyMessageType) ((Handler)inst).HandleMessage((MyMessageType)message); }
var lambda = Expression.Lambda<Action<object, Message>>(ifExpr, instExpr, paramExpr);
var compiled = lambda.Compile();
Action<Message> hook = x => compiled(instance, x);

hook(new MyMessageType());
var type=typeof(处理程序);
var instance=Activator.CreateInstance(类型);
var method=type.GetMethod(“HandleMessage”,BindingFlags.Instance | BindingFlags.Public);
var originalType=类型;
//循环直到我们找到想要的类型。
而(!(type.IsGenericType)| type.GetGenericTypeDefinition()!=typeof(EncasulatedMessageHandler))
{
type=type.BaseType;
if(type==null)
抛出新ArgumentOutOfRangeException(“类型”);
}
var messageType=type.GetGenericArguments()[0];//MyMessageType
//使用表达式创建一个我们可以使用的方法。
var instExpr=Expression.Parameter(typeof(object),“instance”);
var parametexpr=Expression.Parameter(类型为(消息),“消息”);
//(处理者)实例;
var instCastExpr=Expression.Convert(instExpr,originalType);
//(MyMessageType)消息
var castExpr=Expression.Convert(参数xpr,消息类型);
//((Handler)inst).HandleMessage((MyMessageType)消息)
var invokeExpr=Expression.Call(instCastExpr,method,castExpr);
//if(message是MyMessageType)((Handler)inst.HandleMessage((MyMessageType)message);
var ifExpr=Expression.IfThen(Expression.TypeIs(paramExpr,messageType),invokeExpr);
//(inst,message)={if(message是MyMessageType)((Handler)inst.HandleMessage((MyMessageType)message);}
var lambda=Expression.lambda(ifExpr、instExpr、paramExpr);
var compiled=lambda.Compile();
actionhook=x=>compiled(实例,x);
钩子(新的MyMessageType());
编辑:除了上面的表达式示例之外,下面的
var type = typeof(Handler);
var instance = Activator.CreateInstance(type);
var method = type.GetMethod("HandleMessage", BindingFlags.Instance | BindingFlags.Public);

var originalType = type;
// Loop until we hit the type we want.
while (!(type.IsGenericType) || type.GetGenericTypeDefinition() != typeof(EncasulatedMessageHandler<>))
{
    type = type.BaseType;
    if(type == null)
        throw new ArgumentOutOfRangeException("type");
}

var messageType = type.GetGenericArguments()[0]; // MyMessageType

// Use expression to create a method we can.
var instExpr = Expression.Parameter(typeof(object), "instance");
var paramExpr = Expression.Parameter(typeof(Message), "message");
// (Handler)instance;
var instCastExpr = Expression.Convert(instExpr, originalType);
// (MyMessageType)message
var castExpr = Expression.Convert(paramExpr, messageType); 
// ((Handler)inst).HandleMessage((MyMessageType)message)
var invokeExpr = Expression.Call(instCastExpr, method, castExpr); 
// if(message is MyMessageType) ((Handler)inst).HandleMessage((MyMessageType)message);
var ifExpr = Expression.IfThen(Expression.TypeIs(paramExpr, messageType), invokeExpr);

// (inst, message) = { if(message is MyMessageType) ((Handler)inst).HandleMessage((MyMessageType)message); }
var lambda = Expression.Lambda<Action<object, Message>>(ifExpr, instExpr, paramExpr);
var compiled = lambda.Compile();
Action<Message> hook = x => compiled(instance, x);

hook(new MyMessageType());
var instance = (IEncapsulatedMessageHandler)Activator.CreateInstance(typeof(Handler));
instance.HandleMessage(new MyMessageType());

public class Message { }

public class MyMessageType : Message { }

public interface IEncapsulatedMessageHandler
{
    void HandleMessage(Message message);
}

public abstract class EncasulatedMessageHandler<T> : IEncapsulatedMessageHandler where T : Message
{
    public abstract void HandleMessage(T message);

    void IEncapsulatedMessageHandler.HandleMessage(Message message)
    {
        var msg = message as T;
        if (msg != null)
            HandleMessage(msg);
    }
}

public class Handler : EncasulatedMessageHandler<MyMessageType>
{
    public override void HandleMessage(MyMessageType message)
    {
        Console.WriteLine("Yo!");
    }
}
public static Func<object, object[], object> ToFastLambdaInvocationWithCache(
   this MethodInfo pMethodInfo
) {
   Func<object, object[], object> cached;
   if (sLambdaExpressionsByMethodInfoCache.TryGetValue(pMethodInfo, out cached))
      return cached;

   var instanceParameterExpression = Expression.Parameter(typeof(object), "instance");
   var argumentsParameterExpression = Expression.Parameter(typeof(object[]), "args");

   var index = 0;
   var argumentExtractionExpressions =
      pMethodInfo
      .GetParameters()
      .Select(parameter =>
         Expression.Convert(
            Expression.ArrayAccess(
               argumentsParameterExpression,
               Expression.Constant(index++)
            ),
            parameter.ParameterType
         )
      ).ToList();

   var callExpression = pMethodInfo.IsStatic
      ? Expression.Call(pMethodInfo, argumentExtractionExpressions)
      : Expression.Call(
         Expression.Convert(
            instanceParameterExpression, 
            pMethodInfo.DeclaringType
         ),
         pMethodInfo,
         argumentExtractionExpressions
      );

   var endLabel = Expression.Label(typeof(object));
   var finalExpression = pMethodInfo.ReturnType == typeof(void)
      ? (Expression)Expression.Block(
           callExpression,
           Expression.Return(endLabel, Expression.Constant(null)), 
           Expression.Label(endLabel, Expression.Constant(null))
        )
      : Expression.Convert(callExpression, typeof(object));

   var lambdaExpression = Expression.Lambda<Func<object, object[], object>>(
      finalExpression,
      instanceParameterExpression,
      argumentsParameterExpression
   );
   var compiledLambda = lambdaExpression.Compile();
   sLambdaExpressionsByMethodInfoCache.AddOrReplace(pMethodInfo, compiledLambda);
   return compiledLambda;
}