【问题标题】:Is it possible to generate dynamic proxy for static class or static method in C#?是否可以在 C# 中为静态类或静态方法生成动态代理?
【发布时间】:2016-12-12 12:02:36
【问题描述】:

我正在尝试提出一种方法,使(静态或实例)方法调用可以被动态代理拦截。我想将它实现为 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 等)开放。

谢谢!

【问题讨论】:

  • 不要。只是避免静态类。坚持使用接口抽象出来的实例类,你会更开心。哦,你可以拦截那些。

标签: c# aop castle-dynamicproxy


【解决方案1】:

完全不可能。

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

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

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

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

【讨论】:

  • @Downvoter:我很想听听这个。你有更好的答案吗?
  • 您能否提供更多关于非虚拟方法的解决方法的详细信息?代理 List 上的 Add 方法是否有效?
  • @Maslow:我可以回答这个问题,但我会伤害你。 List&lt;T&gt; 实现了IList&lt;T&gt;,所以你永远不应该尝试代理类本身;将您的代码设计为始终使用IList&lt;T&gt;,并从您自己的自定义实现开始,或者在您需要该行为时将List&lt;T&gt; 包装起来。
  • 这不是我的代码,我无法重新编译设计为仅与 List 一起使用的 microsoft.dll,我总是写信给 IList,但我试图涵盖的是一个糟糕的行为设计决定给我,然后覆盖它。
  • @Maslow:你是说有一个 Microsoft 库不仅坚持将List&lt;T&gt; 作为某个地方的参数,而且实际上修改了它的内容?这真是令人震惊的糟糕设计。如果您绝对确定不能简单地包装它,请参阅How do I intercept a method call in C#? 的答案
【解决方案2】:

普通拦截策略不可能。

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

我在开源 NConcern AOP Framework 工作。

这是一个简单的 .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();

【讨论】:

    猜你喜欢
    • 2020-08-06
    • 1970-01-01
    • 2011-01-17
    • 2012-07-05
    • 2016-06-26
    • 2018-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多