是否可以在C#中为静态类或静态方法生成动态代理?

是否可以在C#中为静态类或静态方法生成动态代理?,c#,aop,castle-dynamicproxy,C#,Aop,Castle Dynamicproxy,我试图想出一种方法,动态代理可以拦截(静态或实例)方法调用。我想将其实现为c#扩展方法,但仍停留在如何为静态方法生成动态代理上 一些用法: Repository.GetAll<T>().CacheForMinutes(10); Repository.GetAll<T>().LogWhenErrorOccurs(); //or var repo = new Repository(); repo.GetAll<T>().CacheForMinutes(

我试图想出一种方法,动态代理可以拦截(静态或实例)方法调用。我想将其实现为c#扩展方法,但仍停留在如何为静态方法生成动态代理上

一些用法:

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

//or     
var repo = new Repository();
repo.GetAll<T>().CacheForMinutes(10);
repo.GetAll<T>().LogWhenErrorOccurs();
Repository.GetAll().CacheForMinutes(10);
Repository.GetAll().LogWhenErrorOccurs();
//或
var repo=新存储库();
repo.GetAll().CacheForMinutes(10);
repo.GetAll().LogWhenErrorOccurs();
我对任何图书馆开放(林府、castle.dynamic proxy 2等)

谢谢

完全不可能

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

静态方法从来都不是虚拟的,因此不能被代理重写

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

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

完全不可能

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

静态方法从来都不是虚拟的,因此不能被代理重写

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


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

用普通的拦截策略是不可能的

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

我在开源软件上工作

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

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

我的建议是避免使用AOP来“monkey patch”,静态方法只能是“singleton usages shortcut”,而不是主流方法

在您的情况下,将单例模式与shortup和DI(依赖项注入)等静态方法结合使用更容易启用easy proxy模式

例如:

接口

public interface IRepository
{
    IQueryable<T> Query<T>()
        where T : class;
}
公共接口IRepository
{
IQueryable查询()
式中T:类;
}
使用DI的糖(通过工厂)

静态公共类存储库
{
//如果需要,可以将接口(代理)包装在此处。。。
静态私有只读IRepository m_Repository=MyDIFactory.Import();
静态公共IQueryable查询()
T:在哪里上课
{
返回Repository.m_Repository.Query();
}
}
用法

Repository.Query().CacheForMinutes(10);
Repository.Query().LogWhenErrorOccurs();

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

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

我在开源软件上工作

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

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

我的建议是避免使用AOP来“monkey patch”,静态方法只能是“singleton usages shortcut”,而不是主流方法

在您的情况下,将单例模式与shortup和DI(依赖项注入)等静态方法结合使用更容易启用easy proxy模式

例如:

接口

public interface IRepository
{
    IQueryable<T> Query<T>()
        where T : class;
}
公共接口IRepository
{
IQueryable查询()
式中T:类;
}
使用DI的糖(通过工厂)

静态公共类存储库
{
//如果需要,可以将接口(代理)包装在此处。。。
静态私有只读IRepository m_Repository=MyDIFactory.Import();
静态公共IQueryable查询()
T:在哪里上课
{
返回Repository.m_Repository.Query();
}
}
用法

Repository.Query().CacheForMinutes(10);
Repository.Query().LogWhenErrorOccurs();

@Downvoter:我很想听这个。你有更好的答案吗?你能提供更多关于非虚拟方法的解决方法的细节吗?代理列表上的Add方法行吗?@Maslow:我可以回答,但我会帮你的忙<代码>列表实现了
IList
,因此您不应该试图代理类本身;将您的代码设计为始终使用
IList
,或者从您自己的自定义实现开始,或者在需要时使用它包装
列表
。这不是我的代码,我无法重新编译仅用于列表的microsoft.dll,我始终向IList写入,但我想说的是,对我来说,这是一个糟糕的行为设计决策,只是将其覆盖。@Maslow:你是说,有一个Microsoft库不仅坚持将
列表作为ar
Repository.Query<T>().CacheForMinutes(10);
Repository.Query<T>().LogWhenErrorOccurs();