Замок DynamicProxy: получить незафиксированный объект

Я использую 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 по-прежнему является прокси.

Что мне здесь не хватает?

3 ответа

Этот вопрос немного старый, но, надеюсь, мое решение (которое опирается на.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 Castle.

Если у вас нет 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;
   }
}

Я просто использую такой интерфейс

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`

Возможно, есть лучшие варианты сделать это, но это работает и держит мой код в чистоте от ссылок на замки. Надеюсь это поможет.

Если вы создаете прокси на основе наследования (generator.CreateClassProxy<MyClass>()) прокси является целью.

Другие вопросы по тегам