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

发布于 2024-08-29 18:35:01 字数 435 浏览 6 评论 0原文

我试图想出一种方法(静态或实例)方法调用可以被动态代理拦截。我想将其实现为 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 等)。

谢谢!

I am trying to come up with a way that (either static or instance) method calls can be intercepted by dynamic proxy. I want to implement it as c# extension methods but stuck on how to generate dynamic proxy for static methods.

Some usages:

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

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

I am open to any library (linfu, castle.dynamic proxy 2 or etc).

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

感情旳空白 2024-09-05 18:35:01

完全不可能。

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

静态方法从来都不是虚拟的,因此不能被代理覆盖。

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

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

Totally impossible.

In fact, proxies can't even be generated on all instance methods - they have to be virtual, so that the proxy generator can create a derived class and override them.

Static methods are never virtual, and therefore, cannot be overridden by a proxy.

(Technically there's a workaround for non-virtual methods which is to derive the class from MarshalByRefObject, but remoting-based solutions to this are slow and clunky and still won't support static methods.)

Given that your class is named Repository, I'm going to suggest that you make these methods instance methods instead. These kinds of operations generally shouldn't be static to begin with. If you make them static, you lose a lot of things: Loose coupling, mocking, dependency injection, a certain amount of unit testability, and - as you've just discovered - proxying and interception.

月牙弯弯 2024-09-05 18:35:01

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

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

我致力于开源 NConcern AOP 框架

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

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

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

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

使用 DI连接

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

糖(通过工厂)

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();

Impossible with common interception strategies.

But most of AOP Framework working at compile time can do it. (example : PostSharp)

I work on an open source NConcern AOP Framework.

This is a simple .NET AOP Framework allowing interception at runtime by swaping methods.

It can do its job for virtual methods, non virtual methods and static method without any factory pattern and inheritance needs.

My recommandation is avoid use AOP to "monkey patch" and static methods must be only "singleton usages shortcut", not a mainstream.

in your case it is easier to use singleton pattern with static methods as shortcup and DI (Dependency Injection) to enable easy proxy pattern.

Example :

interface

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

the sugar using DI (via a factory)

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>();
    }
}

Usage

Repository.Query<T>().CacheForMinutes(10);
Repository.Query<T>().LogWhenErrorOccurs();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文