我正在使用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 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。
我只是使用这样的界面
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>()
),则代理是目标。
如果您没有可用的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;
}
}