1

我试图想出一种方法,可以通过动态代理拦截(静态或实例)方法调用。我想将它实现为 c#扩展方法,但坚持如何为静态方法生成动态代理。

一些用法:

Repository.GetAll<T>().CacheForMinutes(10);
Repository.GetAll<T>().LogWhenErrorOccurs();

//or     
var repo = new Repository();
repo.GetAll<T>().CacheForMinutes(10);
repo.GetAll<T>().LogWhenErrorOccurs();

我对任何图书馆(linfu、castle.dynamic proxy 2 等)开放。

谢谢!

4

2 回答 2

9

完全不可能。

事实上,代理甚至不能在所有实例方法上生成——它们必须是虚拟的,以便代理生成器可以创建派生类并覆盖它们。

静态方法永远不是虚拟的,因此不能被代理覆盖。

(从技术上讲,有一个非虚拟方法的解决方法是从 派生类MarshalByRefObject,但是基于远程处理的解决方案缓慢且笨拙,并且仍然不支持静态方法。)

鉴于您的类名为Repository,我将建议您将这些方法改为实例方法。这些类型的操作通常不应该static开始。如果你制作它们static,你会失去很多东西:松散耦合、模拟、依赖注入、一定数量的单元可测试性,以及——正如你刚刚发现的——代理和拦截。

于 2010-04-23T02:29:06.723 回答
0

用常见的拦截策略是不可能的。

但是大多数在编译时工作的 AOP 框架都可以做到。(例如:PostSharp)

我在一个开源的NConcern AOP 框架上工作。

这是一个简单的 .NET AOP 框架,允许在运行时通过交换方法进行拦截。

它可以为虚拟方法、非虚拟方法和静态方法完成它的工作,而无需任何工厂模式和继承需求。

我的建议是避免使用 AOP 来“猴子补丁”,静态方法必须只是“单例用法快捷方式”,而不是主流。

在您的情况下,使用带有静态方法的单例模式作为快捷方式和 DI(依赖注入)来启用简单的代理模式会更容易。

例子 :

界面

public interface IRepository
{
    IQueryable<T> Query<T>()
        where T : class;
}

使用 DI 的糖(通过工厂)

static public class Repository
{
    //You can wrap the interface (proxy) here if you need...
    static private readonly IRepository m_Repository = MyDIFactory.Import<IRepository>();

    static public IQueryable<T> Query<T>()
        where T : class
    {
        return Repository.m_Repository.Query<T>();
    }
}

用法

Repository.Query<T>().CacheForMinutes(10);
Repository.Query<T>().LogWhenErrorOccurs();
于 2016-12-11T11:56:10.983 回答