在C#中实现动态代理的最佳方式是什么?

5

我需要在C#中创建一个动态代理。 我希望这个类能够包装另一个类,并承担它的公共接口,转发对这些函数的调用:

class MyRootClass
{
    public virtual void Foo()
    {
        Console.Out.WriteLine("Foo!");
    }

}

interface ISecondaryInterface
{
    void Bar();
}

class Wrapper<T> : ISecondaryInterface where T: MyRootClass
{
    public Wrapper(T otherObj)
    {
    }

    public void Bar()
    {
        Console.Out.WriteLine("Bar!");
    }
}

这是我想要使用它的方式:

Wrapper<MyRootClass> wrappedObj = new Wrapper<MyRootClass>(new MyRootClass());
wrappedObj.Bar();
wrappedObj.Foo();

生产:

Bar!
Foo!

有什么想法吗?

最简单的方法是什么?

最好的方法是什么?

非常感谢。

更新

我尝试遵循Wernight的建议,使用C#4.0动态代理来实现这一点。不幸的是,我还是卡住了。代理的重点是模拟期望的其他接口(通常情况下)。使用DynamicObject需要我更改所有此类客户端以使用“dynamic”而不是“ISecondaryInterface”。

是否有一种方法可以获得代理对象,使其在包装A时静态地支持A的接口;并且当它包装B时,宣传它支持B的接口?

更新2

例如:

class MySecretProxy : DynamicObject, ISecondaryInterface
{
    public override void TryInvokeMember(...) { .. }

    // no declaration of Bar -- let it be handled by TryInvokeMember
 }

1
你怎么才能让这样的东西编译通过呢?Wrapper 没有 Foo 方法... - BFree
5个回答

7

.NET 4 DynamicObject可以帮助你实现这一目标。

早期的.NET框架可以使用:

  • Aspect#
  • Encase AOP
  • Spring.NET
  • Aspect.NET
  • AspectDNG
  • Dynamic Proxy
  • Compose*
  • Loom.NET
  • PostSharp

这些框架都使用了许多技术来注入代码,包括在方法执行前后注入代码。这些技术通常可以分为四类。

  • MSIL注入 - 在正在执行的方法体中注入MSIL代码。(Post sharp)
  • 运行时动态注入 - 使用反射等技术,动态调用方法。
  • Type builder注入 - 相关于运行时注入,我们创建一个基于要代理的类型的类型,然后通过此类型传递请求。(Dynamic Proxy)
  • 容器注入 - 请求通过容器传递,容器在方法执行前后调用代码。

请参见完整文章

我知道Castle ProjectDynamic Proxy经常被使用(例如在Moq中只是一个大项目的名称)。


回复更新主题

你写的代码将无法编译。动态代理是运行时生成的代码,因此你必须以某种方式创建要代理的类的具体实例。也许你正在寻找进行AOP(面向切面编程)。

class MySecretProxy<T> : DynamicObject, T where T : new()
{
    private T _instance = new T();

    public override void TryInvokeMember(...) { ... }
}

MySecretProxy<Bar> bar;

1
关于这个主题的写作很好,提供了一个不错的实际例子。但是我仍然无法解决我的问题(请参见问题更新)。 - gap
4
你所拥有的代码无法编译,它会给出错误提示:"无法从 'T' 派生,因为它是一个类型参数"。 - Aaron Stainback

3

2
我简要地看了一下,这促使我在这里问这个问题:“最简单的方法是什么?”它似乎是一个相当大的库,而我只会使用其中一个小功能。有更简单的方法吗? - gap
2
你为什么担心库的大小?你只需要使用你想要的功能。实际上,这个文件(Castle.Core.dll)只有290KB。如果这个库能够满足你的需求,那么使用它几乎肯定比自己重新发明这个轮子更容易。 - Adam Ralph
总的来说,我所指的并不是程序集的大小,而是需要学习和内化的大量类/接口的数量,以便正确使用它们。这是一个培训问题,而不是空间问题。 - gap
如果你只打算使用库中的“一个小功能”,那么为什么要同时学习所有其他“功能”呢?如果它们目前对你没有兴趣,你可以忽略它们。这就像反对使用.NET框架本身的库(例如mscorlib)中的“一个小功能”,只是因为它有很多其他“功能”。 - Adam Ralph

1
如果目标类型是接口或从MarshalByRefObject派生的话,您可以使用RealProxy来实现这一点。

0

你可能想看一下 linfu,它包含了一个动态代理机制。


0

我知道NHibernate用于懒加载的代理

Castle

Linfu

Spring ByteCode


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接