使用Reflection.Emit实现接口

发布于 2024-09-13 21:43:37 字数 597 浏览 1 评论 0原文

假设我有以下接口:

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

}

并想要生成一个如下所示的类(使用反射发射)。

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);
  }
}

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

Let's say that I have the following interface:

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

孤星 2024-09-20 21:43:37

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

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

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

    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);
    }

问候,

-道格

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:

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.

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);
    }

Regards,

-Doug

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文