问题
I'm using Castle DynamicProxy to add an interceptor to my types. Now I need to get the underlying base type (NOT the proxy itself).
I found a few hints on SO that suggested to use the ProxyUtil class like this:
object realInstance = ProxyUtil.GetUnproxiedInstance(proxyInstance);
This does not seem to work as
bool isProxy = ProxyUtil.IsProxy(realInstance);
is always true.
I also tried using the following code snippet, which is essentially what ProxyUtil is doing:
var accessor = proxyInstance as IProxyTargetAccessor;
var realInstance = accessor.DynProxyGetTarget();
with the same results, realInstance is still a proxy.
What am I missing here?
回答1:
This question is a little old but hopefully my solution (which relies on .NET 4+) will help someone.
Having created a proxy as follows:
ProxyGenerator generator = new ProxyGenerator();
MyClass proxy = generator.CreateClassProxyWithTarget(underlying, new MyInterceptor(this));
I have been able to get the underlying target with the following method:
internal static TType UnwrapProxy<TType>(TType proxy)
{
if (!ProxyUtil.IsProxy(proxy))
return proxy;
try
{
dynamic dynamicProxy = proxy;
return dynamicProxy.__target;
}
catch (RuntimeBinderException)
{
return proxy;
}
}
It relies on the internal implementation of Castle - i.e. that the generated proxy has a __target member. It is nice and self contained though and backed up with a unit test or two, we should catch any changes should a later version of Castle break this. This is using v3.2.0.0 of Castle.
回答2:
If you don't have an invocation
object available, or if you observe 'Castle.Proxies.IXeroServiceProxy.__target' is inaccessible due to its protection level
when trying @s1mm0t's answer, you can try the following code which uses reflection instead of 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;
}
}
回答3:
I simply use an interface like this
public interface IMarker
{
Type ActualType { get; }
}
add it to my proxy and intercept it:
public class MyInterceptor<T> : IInterceptor
...
if (invocation.Method.DeclaringType == typeof(IMarker))
{
if (invocation.Method.Name.Equals("get_ActualType"))
{
invocation.ReturnValue = typeof(T);
return;
}
}
So in the end i only have to check
if( obj is IMarker )
Type t = (obj as IMarker).ActualType`
Maybe there are better options to do it, but it works and keeps my code clean from castle references. Hope this helps.
回答4:
If you are building an inheritance-based proxy (generator.CreateClassProxy<MyClass>()
) the proxy is the target.
来源:https://stackoverflow.com/questions/11082911/castle-dynamicproxy-get-unproxied-object