如何将现有对象实例包装到DispatchProxy中?

时间:2017-07-05 09:50:27

标签: c# .net .net-core realproxy

我在.NET Core中寻找RealProxy替换,而issue将我转发到DispatchProxy

它有简单的API,但不清楚如何将现有的对象包装到代理中。
例如,有这个界面:

interface IFoo
{
    string Bar(int boo);
}

和这个实现:

class FooImpl : IFoo
{
    public string Bar(int boo)
    {
        return $"Value {boo} was passed";
    }
}

如何得到我想要的东西?

class Program
{
    static void Main(string[] args)
    {
        var fooInstance = new FooImpl();
        var proxy = DispatchProxy.Create<IFoo, FooProxy>();

        var s = proxy.Bar(123);

        Console.WriteLine(s);
    }
}

class FooProxy : DispatchProxy
{
    protected override object Invoke(MethodInfo targetMethod, object[] args)
    {
        return targetMethod.Invoke(/* I need fooInstance here */, args);
    }
}

由于DispatchProxy后代必须具有无参数构造函数,我唯一的想法是发明一些方法,如下所示:

class FooProxy : DispatchProxy
{
    private object target;

    public void SetTarget(object target)
    {
        this.target = target;
    }

    protected override object Invoke(MethodInfo targetMethod, object[] args)
    {
        return targetMethod.Invoke(target, args);
    }
}

并以这种方式使用它:

var fooInstance = new FooImpl();
var proxy = DispatchProxy.Create<IFoo, FooProxy>();

((FooProxy)proxy).SetTarget(fooInstance);

// the rest of code...

这是正确的方法吗?

2 个答案:

答案 0 :(得分:4)

您说得对,除了将生成的IFoo强制转换为已知代理类型(FooProxy)并在FooProxy上使用自定义方法或属性之外,没有其他选择。没有公共API来添加构造函数参数或返回代理作为实现类型。但是,DispatchProxy.Create()将返回FooProxy子类的实例,其类型在运行时通过反射和IL发射生成。

如果您正在寻找快速包装实现并替换接口方法/虚拟方法的其他方法,我建议使用模拟框架(FakeItEasy,Moq,NSubstitute等)。

答案 1 :(得分:1)

您需要创建自己的继承自DispatchProxy的泛型类,并具有自己的静态Create,该类具有来自target类型的额外参数。

示例

public class AopAction<T>:DispatchProxy
{
  #region Private Fields
  private Action<MethodInfo,object[],object> ActAfter;
  private Action<MethodInfo,object[]> ActBefore;
  private Action<MethodInfo,object[],Exception> ActException;
  private T Decorated;
  #endregion Private Fields

  #region Public Methods
  public static T Create(T decorated,Action<MethodInfo,object[]> actBefore = null,Action<MethodInfo,object[],object> actAfter = null,Action<MethodInfo,object[],Exception> actException = null)
  {
    object proxy = Create<T,AopAction<T>>();
    SetParameters();
    return (T)proxy;
    void SetParameters()
    {
      var me = ((AopAction<T>)proxy);
      me.Decorated = decorated == default ? throw new ArgumentNullException(nameof(decorated)) : decorated;
      me.ActBefore = actBefore;
      me.ActAfter = actAfter;
      me.ActException = actException;
    }
  }
  #endregion Public Methods

  #region Protected Methods
  protected override object Invoke(MethodInfo targetMethod,object[] args)
  {
    _ = targetMethod ?? throw new ArgumentException(nameof(targetMethod));

    try
    {
      ActBefore?.Invoke(targetMethod,args);
      var result = targetMethod.Invoke(Decorated,args);
      ActAfter?.Invoke(targetMethod,args,result);
      return result;
    }
    catch(Exception ex)
    {
      ActException?.Invoke(targetMethod,args,ex);
      throw ex.InnerException;
    }
  }
  #endregion Protected Methods
}

使用您的示例

var proxy=AopAction<IFoo>.Create(new FooImpl());