Castle DynamicProxy:获取未经过代理的对象

问题描述 投票:6回答:4

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

我在SO上找到了一些提示,建议使用ProxyUtil类,如下所示:

object realInstance = ProxyUtil.GetUnproxiedInstance(proxyInstance);

这似乎不起作用

bool isProxy = ProxyUtil.IsProxy(realInstance);

总是如此。

我还尝试使用以下代码片段,这实际上是ProxyUtil正在做的事情:

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

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

我在这里错过了什么?

.net castle-dynamicproxy
4个回答
9
投票

这个问题有点旧,但希望我的解决方案(依赖.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。


1
投票

我只是使用这样的界面

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`

也许有更好的选择,但它可以工作,并保持我的代码清理城堡参考。希望这可以帮助。


1
投票

如果要构建基于继承的代理(generator.CreateClassProxy<MyClass>()),则代理是目标。


0
投票

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

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;
   }
}
© www.soinside.com 2019 - 2024. All rights reserved.