8

我正在使用 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 仍然是代理。

我在这里想念什么?

4

4 回答 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 破坏了这一点,我们应该捕捉到任何变化。这是使用城堡的 v3.2.0.0。

于 2013-10-04T07:37:13.680 回答
6

如果您没有invocation可用的对象,或者您'Castle.Proxies.IXeroServiceProxy.__target' is inaccessible due to its protection level在尝试@s1mm0t的答案时观察到,您可以尝试使用反射而不是以下代码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;
   }
}
于 2019-04-14T01:59:42.847 回答
2

我只是使用这样的界面

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`

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

于 2012-06-22T21:20:53.620 回答
1

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

于 2012-06-22T23:24:00.780 回答