使用 Reflection.Emit 实现接口 [英] Using Reflection.Emit to implement a interface

查看:73
本文介绍了使用 Reflection.Emit 实现接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下界面:

public interface IMyService
{
   void SimpleMethod(int id);
   int Hello(string temp);

}

并且想要生成一个看起来像这样的类(使用反射发射).

And want to generate a class that looks like this (using reflection emit).

public class MyServiceProxy : IMyService
{
  IChannel _channel;

  public MyServiceProxy(IChannel channel)
  {
    _channel = channel;
  }

  public void SimpleMethod(int id)
  {
    _channel.Send(GetType(), "SimpleMethod", new object[]{id});
  }

  public int Hello(string temp)
  {
    return (int)_channel.Request(temp);
  }
}

我该怎么做?我检查了各种动态代理和模拟框架.它们有点复杂,不太容易理解(而且我不想要外部依赖).为接口生成代理应该不难.谁能告诉我怎么做?

How do I do it? I've checked various dynamic proxies and mock frameworks. They are bit complex and not very easy to follow (and I do not want an external dependency). It shouldn't be that hard to generate a proxy for an interface. Can anyone show me how?

推荐答案

总而言之,我将同意其他人的意见.我使用过 Castle 的 DynamicProxy,我认​​为它很棒.你可以用它做一些非常神奇和强大的事情.也就是说,如果您仍在考虑自己编写,请继续阅读:

All in all I'm going to agree with others' comments. I've used Castle's DynamicProxy and I think it's wonderful. You can do some really amazing and powerful stuff with it. That said, if you're still considering writing your own, read on:

如果您对发出 IL 不感兴趣,可以使用一些使用 Lambda 表达式的新技术来生成代码.然而,这一切都不是一项微不足道的任务.

If you're not excited about emitting IL, there are some new techniques using Lambda expressions that you can use to generate code. None of this is a trivial task, however.

以下是我如何使用 Lambda 表达式为任何 .NET 事件生成动态事件处理程序的示例.您可以使用类似的技术来生成动态接口实现.

Here's an example of how I've used Lambda expressions to generate a dynamic event handler for any .NET event. You could use a similar technique to generate a dynamic interface implementation.

    public delegate void CustomEventHandler(object sender, EventArgs e, string eventName);

    Delegate CreateEventHandler(EventInfo evt, CustomEventHandler d)
    {
        var handlerType = evt.EventHandlerType;
        var eventParams = handlerType.GetMethod("Invoke").GetParameters();

        //lambda: (object x0, EventArgs x1) => d(x0, x1)

        // This defines the incoming parameters of our dynamic method.  
        // The method signature will look something like this:
        // void dynamicMethod(object x0, EventArgs<T> x1)
        // Each parameter is dynamically determined via the 
        // EventInfo that was passed.
        var parameters = eventParams.Select((p, i) => Expression.Parameter(p.ParameterType, "x" + i)).ToArray();

        // Get the MethodInfo for the method we'll be invoking *within* our
        // dynamic method.  Since we already know the signature of this method,
        // we supply the types directly.
        MethodInfo targetMethod = d.GetType().GetMethod(
            "Invoke", 
            new Type[] { typeof(object), typeof(EventArgs), typeof(string) }
            );

        // Next, we need to convert the incoming parameters to the types
        // that are expected in our target method.  The second parameter,
        // in particular, needs to be downcast to an EventArgs object
        // in order for the call to succeed.
        var p1 = Expression.Convert(parameters[0], typeof(object));
        var p2 = Expression.Convert(parameters[1], typeof(EventArgs));
        var p3 = Expression.Constant(evt.Name);

        // Generate an expression that represents our method call.  
        // This generates an expression that looks something like:
        // d.Invoke(x0, x1, "eventName");
        var body = Expression.Call(
            Expression.Constant(d),
            targetMethod,
            p1,
            p2,
            p3
        );

        // Convert the entire expression into our shiny new, dynamic method.
        var lambda = Expression.Lambda(body, parameters.ToArray());

        // Convert our method into a Delegate, so we can use it for event handlers.
        return Delegate.CreateDelegate(handlerType, lambda.Compile(), "Invoke", false);
    }

问候,

-道格

这篇关于使用 Reflection.Emit 实现接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆