【问题标题】:Castle DynamicProxy: Get unproxied objectCastle DynamicProxy:获取未代理的对象
【发布时间】:2012-06-20 10:14:14
【问题描述】:

我正在使用 Castle DynamicProxy 为我的类型添加一个拦截器。 现在我需要获取底层的基本类型(而不是代理本身)。

我在 SO 上发现了一些提示,建议像这样使用 ProxyUtil 类:

object realInstance = ProxyUtil.GetUnproxiedInstance(proxyInstance);

这似乎不起作用

bool isProxy = ProxyUtil.IsProxy(realInstance);

总是正确的。

我也尝试使用下面的代码 sn-p,本质上就是 ProxyUtil 正在做的事情:

var accessor = proxyInstance as IProxyTargetAccessor;
var realInstance = accessor.DynProxyGetTarget();

结果相同,realInstance 仍然是一个代理。

我在这里错过了什么?

【问题讨论】:

    标签: .net castle-dynamicproxy


    【解决方案1】:

    这个问题有点老了,但希望我的解决方案(依赖于 .NET 4+)能对某人有所帮助。

    已创建如下代理:

    ProxyGenerator generator = new ProxyGenerator();
    MyClass proxy = generator.CreateClassProxyWithTarget(underlying, new MyInterceptor(this));
    

    我已经能够通过以下方法得到底层目标:

    internal static TType UnwrapProxy<TType>(TType proxy)
    {
        if (!ProxyUtil.IsProxy(proxy))
            return proxy;
    
        try
        {
            dynamic dynamicProxy = proxy;
            return dynamicProxy.__target;
        }
        catch (RuntimeBinderException)
        {
            return proxy;
        }
    }
    

    它依赖于 Castle 的内部实现——即生成的代理有一个 __target 成员。虽然它很好,而且是独立的,并且有一个或两个单元测试支持,如果更高版本的 Castle 破坏了这一点,我们应该捕捉到任何变化。这里使用的是 Castle v3.2.0.0。

    【讨论】:

    • dynamic 在这里获胜。节拍试图反映到它。那是史诗般的失败。
    • 在撰写本文时 - 即 2019 年 4 月 14 日 - 此答案中的代码导致 'Castle.Proxies.IXeroServiceProxy.__target' is inaccessible due to its protection level。我不会投反对票,因为它可能在当时与 dynamic 实现以及 DynamicProxy 类的不同版本一起工作。
    【解决方案2】:

    如果您没有可用的invocation 对象,或者在尝试@s1mm0t 的答案时观察到'Castle.Proxies.IXeroServiceProxy.__target' is inaccessible due to its protection level,您可以尝试使用反射而不是@ 的以下代码987654323@:

    public static T UnwrapProxy<T>(T proxy) {
       if(!ProxyUtil.IsProxy(proxy)) {
          return proxy;
       }
       try {
          const System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance;
          var proxyType = proxy.GetType();
          var instanceField = proxyType.GetField("__target", flags);
          var fieldValue = instanceField.GetValue(proxy);
          return (T) fieldValue;
       }
       catch(RuntimeBinderException) {
          return proxy;
       }
    }
    

    【讨论】:

      【解决方案3】:

      我只是使用这样的界面

      public interface IMarker
      {
        Type ActualType { get; }
      }
      

      将其添加到我的代理并拦截它:

      public class MyInterceptor<T> : IInterceptor
      

      ...

      if (invocation.Method.DeclaringType == typeof(IMarker))
      {
        if (invocation.Method.Name.Equals("get_ActualType"))
        {
          invocation.ReturnValue = typeof(T);
          return;
        }
      }
      

      所以最后我只需要检查

      if( obj is IMarker ) 
        Type t = (obj as IMarker).ActualType`
      

      也许有更好的选择,但它可以让我的代码免受城堡引用的影响。 希望这会有所帮助。

      【讨论】:

        【解决方案4】:

        如果您正在构建基于继承的代理 (generator.CreateClassProxy&lt;MyClass&gt;()),则代理目标。

        【讨论】:

        • 我正在使用CreateClassProxyWithTarget&lt;MyClass&gt;(instance, interceptor) 创建代理。问题在于 NHibernate 失败,因为它认为它应该映射代理,而不是目标。
        猜你喜欢
        • 2012-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-29
        • 1970-01-01
        • 2012-03-31
        相关资源
        最近更新 更多