如何在C#中创建一个简单的动态代理

时间:2011-12-05 14:41:59

标签: c# .net reflection proxy aop

我想构建一个动态代理对象,以便为对象添加某些功能。

基本上我想接收一个对象,用一个看起来与我原来的相同的对象包装它,并拦截所有的调用。

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就是这样做的。

8 个答案:

答案 0 :(得分:35)

您可以使用DynamicObjectImpromptuInterface的组合执行此操作,但您必须拥有一个实现要代理的功能和属性的接口。

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)

我应该早点写出来,但没关系。

我的问题有一个特殊的“问题”我需要能够代理类而不是接口。

有两种解决方案:

  1. Real Proxy和朋友们,基本上意味着使用.Net Remoting。需要一个从ContextBoundObject继承。

  2. 使用System.Reflection.Emit spring建立代理,您也可以查看ProxyFactoryObject的代码。以下是another上的articlessubject

  3. 顺便说一下,第二种方法有相当大的局限性,你不能代理非虚方法。

答案 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完全覆盖原始类。