我想构建一个动态代理对象,以便为对象添加某些功能。
基本上我想接收一个对象,用一个看起来与我原来的相同的对象包装它,并拦截所有的调用。
class Wrapper : DynamicProxy// dynamic proxy is not a reall class, but i guess something like this exists...
{
public static T Wrap(T obj)
{
return (T) new Wrapper(obj);
}
public override object InterceptCall(MethodInfo info, object[] args)
{
// do stuff
}
}
为了澄清,我想做一些与WCF渠道工厂类似的事情......
我正在添加一个赏金,因为我需要一个很好的方法来代理类(不是接口)和处理非虚方法(就像我继承并在“new”关键字下添加了一个methond)。 我确信这一切都很可能,因为.Net就是这样做的。
答案 0 :(得分:35)
您可以使用DynamicObject和ImpromptuInterface的组合执行此操作,但您必须拥有一个实现要代理的功能和属性的接口。
public interface IDoStuff
{
void Foo();
}
public class Wrapper<T> : DynamicObject
{
private readonly T _wrappedObject;
public static T1 Wrap<T1>(T obj) where T1 : class
{
if (!typeof(T1).IsInterface)
throw new ArgumentException("T1 must be an Interface");
return new Wrapper<T>(obj).ActLike<T1>();
}
//you can make the contructor private so you are forced to use the Wrap method.
private Wrapper(T obj)
{
_wrappedObject = obj;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
try
{
//do stuff here
//call _wrappedObject object
result = _wrappedObject.GetType().GetMethod(binder.Name).Invoke(_wrappedObject, args);
return true;
}
catch
{
result = null;
return false;
}
}
}
你当然可以选择失去类型安全性,然后使用我展示的DynamicObject,然后放弃鸭子投射。
我制作了此对象代理的transparant可扩展版本,并将其开源here。
答案 1 :(得分:14)
我应该早点写出来,但没关系。
我的问题有一个特殊的“问题”我需要能够代理类而不是接口。
有两种解决方案:
Real Proxy和朋友们,基本上意味着使用.Net Remoting。需要一个从ContextBoundObject继承。
使用System.Reflection.Emit spring建立代理,您也可以查看ProxyFactoryObject的代码。以下是another上的articles三subject。
顺便说一下,第二种方法有相当大的局限性,你不能代理非虚方法。
答案 2 :(得分:13)
答案 3 :(得分:5)
看看PostSharp。 我不知道如何在vanilla .Net中执行您想要的操作,但PostSharp提供的内容类似于“OnMethodBoundaryAspect”,可用于替换或包装方法内的代码。
我用它来做日志,参数验证,异常处理等事情。
有一个免费的社区版,应该适合你。您需要在开发计算机上安装它,以及您使用的任何构建服务器。
答案 4 :(得分:3)
以下是简单示例Dynamic Proxy Creation Using C# Emit
您还可以使用像PostSharp
这样的AOP框架答案 5 :(得分:2)
另一个选项是ContextBoundObject
。
有一篇关于CodeProject的文章大约8 - 9年前使用这种方法来跟踪方法调用。
答案 6 :(得分:0)
为了在类中的每个函数之前和之后添加任何功能,Real代理是一种很好的方法。
所以现在在T中可以是任何TestClass。为TestClass创建这样的实例 -
var _instance =(object)DynamicProxy(TestClass).GetTransparentProxy();
动态代理的代码 -
class DynamicProxy<T> : RealProxy
{
readonly T decorated;
public DynamicProxy(T decorated) : base(typeof(T))
{
this.decorated = decorated;
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase as MethodInfo;
string fullMethodName = $"{methodInfo.DeclaringType.Name}.{methodCall.MethodName}";
try
{
var result = methodInfo.Invoke(decorated, methodCall.InArgs);
return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
}
catch (Exception e)
{
return new ReturnMessage(e, methodCall);
}
finally
{
}
}
}
答案 7 :(得分:0)
除非您让CLR钩住对该对象的每个方法/属性调用并将其重定向到您创建的伪造对象,否则您将无法拦截对静态,非虚拟或私有成员的所有调用。您可以使用.NET Profiler API来实现。例如,TypeMock隔离器使用它监视应用程序的执行,并在调用方法时CLR通知Typemock隔离器,该隔离器允许Isolator完全覆盖原始类。