How to wrap existing object instance into Dispatch

2020-06-18 03:48发布

I'm looking for RealProxy replacement in .NET Core, and this issue forwards me to DispatchProxy.

It has simple API, but it's unclear, how to wrap existing object into proxy.
E.g., having this interface:

interface IFoo
{
    string Bar(int boo);
}

and this implementation:

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

how to get what I want?

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

Since DispatchProxy descendants must have parameterless constructor, the only idea I have is to invent some method, like this:

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

and use it this way:

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

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

// the rest of code...

Is this correct approach?

2条回答
Evening l夕情丶
2楼-- · 2020-06-18 04:15

You are right that there is no other option here than to cast the generated IFoo to the known proxy type (FooProxy) and use a custom method or property on FooProxy. There is no public API to add constructor arguments or return the proxy as the implementation type. However, DispatchProxy.Create() will return an instance of a subclass of FooProxy whose type is generated at runtime via reflection and IL emitting.

If you are looking at other ways to quickly wrap an implementation and replace interface methods / virtual methods, I suggest using mocking frameworks instead (FakeItEasy, Moq, NSubstitute etc.).

查看更多
Explosion°爆炸
3楼-- · 2020-06-18 04:27

You need to create your own Generic class that inherit from DispatchProxy and has own static Create that has an extra parameter from type target.

example

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
}

to use your example

var proxy=AopAction<IFoo>.Create(new FooImpl());
查看更多
登录 后发表回答