C# 使用标准.NET框架基本实现类AOP属性

C# 使用标准.NET框架基本实现类AOP属性,c#,.net,attributes,aop,C#,.net,Attributes,Aop,可能重复: 我想实现这样的功能: [Atomic] public void Foo() { /* foo logic */ } 其中,[Atomic]属性是一个属性,它将函数逻辑包装在事务范围内: using(var scope = new TransactionScope()) { /* foo logic */ scope.Complete(); } 如何编写这样的属性 我以前也问过基本相同的问题,我知道这可以使用AOP来完成,但我没有提到

可能重复:

我想实现这样的功能:

[Atomic]
public void Foo()
{           
    /* foo logic */
}
其中,
[Atomic]
属性是一个属性,它将函数逻辑包装在事务范围内:

using(var scope = new TransactionScope())
{
    /* foo logic */
    scope.Complete();
}
如何编写这样的属性

我以前也问过基本相同的问题,我知道这可以使用AOP来完成,但我没有提到我正在寻找一些最简单的概念证明实现或有用的文章,这些文章可以帮助我使用纯.NET框架编写本文(我假设使用
RealProxy
MarshalByRefObject
类型,我已经阅读了与浏览相关的问题)


我需要准确地解决这个示例。这似乎是一件基本的事情,所以我想从零开始学习如何做到这一点。现在不需要安全和灵活。

属性都是元数据-这就是它们的全部

有许多工具可以利用这种元数据,但是这种工具需要知道该属性

像PostSharp这样的AOP工具读取这样的元数据,以便知道将方面编织到代码中的内容和位置


简而言之-只需编写一个
原子属性
就不会给您任何东西-您需要通过一个了解该属性的工具来传递已编译的程序集,并执行“操作”为了实现AOP,对它进行修改。

这根本不是一件基本的事情。仅仅因为方法有一个属性,就不会运行额外的代码,因此没有地方放置您的
事务范围
代码

您需要做的是,在应用程序启动时,使用反射来迭代程序集中每个类上的每个方法,并找到标记有
AtomicAttribute
的方法,然后围绕该对象编写一个自定义代理。然后以某种方式让其他一切调用您的代理,而不是真正的实现,可能是usi支持依赖注入框架

大多数AOP框架在构建时都会这样做。例如,PostSharp在VisualStudio构建程序集之后运行。它扫描程序集并重写IL代码以包含代理和AOP拦截器。这样,程序集在运行时就可以正常运行,但IL与您最初编写的有所不同

这似乎是一件基本的事情

这是(许多)容易理解概念但根本不容易实现的事情之一

根据,属性在.NET中不起任何作用。它们的存在只是为了其他代码(或开发人员)可以在以后查看它们。请将其视为一个奇特的注释

记住这一点,您可以这样编写属性

public class AtomicAttribute : Attribute { } 
现在最困难的部分是,您必须编写一些代码来扫描该属性,并更改代码的行为

考虑到C#是一种编译语言,并且考虑到.NET CLR的规则,理论上有三种方法可以做到这一点

  • 钩住C#编译器,使其在看到该属性时输出不同的代码。
    这似乎很好,但根本不可能 现在,也许是 project将来可能会允许这样做,但现在,您不能这样做

  • 编写一些东西,在C#编译器将.NET程序集转换为MSIL后扫描它,并更改MSIL。
    基本上就是这样做的。扫描和重写MSIL很困难。有这样的库可以提供帮助,但这仍然是一个非常困难的问题。它还可能干扰调试器,等等

  • 使用.NET评测API在程序运行时监视程序,每次看到具有该属性的函数调用时,都将其重定向到其他包装函数。
    这可能是最简单的选择(尽管仍然非常困难),但缺点是您的程序现在必须在探查器下运行。这在您的开发PC上可能很好,但如果您尝试部署它,将导致一个巨大的问题。此外,使用此方法可能会对性能造成很大的影响

  • 在我看来,最好的办法是创建一个包装器函数来设置事务,然后向它传递一个lambda来执行实际工作。如下所示:

    public static class Ext 
    {
        public static void Atomic(Action action) 
        {
            using(var scope = new TransactionScope()) 
            {
                action();
                scope.Commit();
            }
        }
    }
    
    .....
    
    using static Ext; // as of VS2015
    
    public void Foo()
    {
        Atomic(() => {
            // foo logic
        }
    }
    

    这方面的计算机科学术语是

    也许可以使用IoC容器解析所有对象? 您可以为您的类型配置拦截器,并在拦截器中检查调用的方法是否用该属性修饰。您可以缓存该信息,这样您就不必在每次方法调用时使用反射

    所以当你这样做的时候:

    var something = IoC.Resolve<ISomething>();
    
    var something=IoC.Resolve();
    

    something
    不是您已经实现的对象,而是代理。在该代理中,您可以在方法调用之前和之后执行任何您想要的操作。

    如果您这样做是为了自己的教育,这很好,但是如果您这样做是为了解决业务需求,那么它已经在WCF和COM+中为您完成了。谢谢您的时间。我是sta现在我想知道我真正想问的是什么。关于。属性不起任何作用并不完全正确。请看System.Web.Http.AuthorizationAttribute,它处理请求的IPPrincipal的授权。@Polymorphix不,System.Web.Http.AuthorizationAttribute也不起任何作用。当ASP.NET Web API执行它的框架工作时创建类的实例时,它会查找AuthorizeAttribute,如果看到它,它的行为会有所不同,但该属性本身只是坐在那里等待别人查找it@OrionEdwards是的,你完全正确。我的错。@OrionEdwards-关于如何嵌套作用域有什么线索吗?假设我有另一个方法w/c调用Ext.Atomic并在该方法内我会打电话给Foo。我想了解一下这个领域的一些细节,以扩展我对框架的理解,并做一些你在第二段中提到的基本工作。谢谢你的回答。我认为现代程序使用一个IOC容器。所以,这是一条路。看看哪一个是使用代理的AOP,哪一个是中间接受者a