当前位置:  开发笔记 > 编程语言 > 正文

C#:如何在调用事件时触发事件的方法上创建属性?

如何解决《C#:如何在调用事件时触发事件的方法上创建属性?》经验,为你挑选了3个好方法。

在C#或.NET中是否有一种方法可以在调用方法时触发事件的方法上创建属性?理想情况下,我可以在调用方法之前和之后运行自定义操作.

我的意思是这样的:

[TriggersMyCustomAction()]
public void DoSomeStuff()
{
}

我完全不知道怎么做或者根本不可能,但是System.Diagnostic.ConditionalAttribute可能在后台做类似的事情.我不确定.

编辑:我忘了提到由于我的具体情况,性能不是一个问题.



1> Matt..:

此概念用于MVC Web应用程序.

.NET框架4.x版提供了几个属性,这触发动作,如:ExceptionFilterAttribute(异常处理), AuthorizeAttribute(处理授权).两者都定义于System.Web.Http.Filters.

例如,您可以按如下方式定义自己的授权属性:

public class myAuthorizationAttribute : AuthorizeAttribute
{
    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        // do any stuff here
        // it will be invoked when the decorated method is called
        if (CheckAuthorization(actionContext)) 
           return true; // authorized
        else
           return false; // not authorized
    }

}

然后,在您的控制器类中,您将装饰应该使用您的授权的方法,如下所示:

[myAuthorization]
public HttpResponseMessage Post(string id)
{
    // ... your code goes here
    response = new HttpResponseMessage(HttpStatusCode.OK); // return OK status
    return response;
}

每当Post调用该方法时,它都会在执行IsAuthorized方法内部的代码之前调用myAuthorizationAttribute 内的方法.Post

如果返回falseIsAuthorized方法,你发出信号没有获得授权和方法的执行Post中止.


为了理解这是如何工作的,让我们看一个不同的例子:ExceptionFilter它允许使用属性过滤异常,其用法类似于上面所示的AuthorizeAttribute(您可以在这里找到有关其用法的更详细描述).

要使用它,DivideByZeroExceptionFilter从此处ExceptionFilterAttribute显示的类派生类,并覆盖该方法:OnException

public class DivideByZeroExceptionFilter : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext actionExecutedContext)
    {
        if (actionExecutedContext.Exception is DivideByZeroException)
        {
            actionExecutedContext.Response = new HttpResponseMessage() { 
                Content = new StringContent("An error occured within the application.",
                                System.Text.Encoding.UTF8, "text/plain"), 
                StatusCode = System.Net.HttpStatusCode.InternalServerError
                };
        }
    }
}

然后使用以下演示代码触发它:

[DivideByZeroExceptionFilter]
public void Delete(int id)
{
    // causes the DivideByZeroExceptionFilter attribute to be triggered:
    throw new DivideByZeroException(); 
}

现在我们知道它是如何使用的,我们主要对实现感兴趣.以下代码来自.NET Framework.它在IExceptionFilter内部使用接口作为合同:

namespace System.Web.Http.Filters
{
    public interface IExceptionFilter : IFilter
    {
        // Executes an asynchronous exception filter.
        // Returns: An asynchronous exception filter.
        Task ExecuteExceptionFilterAsync(
                    HttpActionExecutedContext actionExecutedContext, 
                    CancellationToken cancellationToken);
    }
}

ExceptionFilterAttribute本身被定义为如下:

namespace System.Web.Http.Filters
{
    // Represents the attributes for the exception filter.
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, 
            Inherited = true, AllowMultiple = true)]
    public abstract class ExceptionFilterAttribute : FilterAttribute, 
            IExceptionFilter, IFilter
    {
        // Raises the exception event.
        // actionExecutedContext: The context for the action.
        public virtual void OnException(
            HttpActionExecutedContext actionExecutedContext)
        {
        }
        // Asynchronously executes the exception filter.
        // Returns: The result of the execution.
        Task IExceptionFilter.ExecuteExceptionFilterAsync(
            HttpActionExecutedContext actionExecutedContext, 
            CancellationToken cancellationToken)
        {
            if (actionExecutedContext == null)
            {
                throw Error.ArgumentNull("actionExecutedContext");
            }
            this.OnException(actionExecutedContext);
            return TaskHelpers.Completed();
        }
    }
}

在里面ExecuteExceptionFilterAsync,OnException调用该方法.因为您已经覆盖了它,如前所示,现在可以通过您自己的代码处理错误.


OwenP的答案PostSharp中还提供了一种商业产品,可以让您轻松完成.以下是如何使用PostSharp执行此操作的示例.请注意,有一个Express版本,即使是商业项目,您也可以免费使用.

PostSharp示例(有关完整说明,请参阅上面的链接):

public class CustomerService
{
    [RetryOnException(MaxRetries = 5)]
    public void Save(Customer customer)
    {
        // Database or web-service call.
    }
}

此属性指定在Save发生异常时最多调用该方法5次.以下代码定义了此自定义属性:

[PSerializable]
public class RetryOnExceptionAttribute : MethodInterceptionAspect
{
    public RetryOnExceptionAttribute()
    {
        this.MaxRetries = 3;
    }

    public int MaxRetries { get; set; }

    public override void OnInvoke(MethodInterceptionArgs args)
    {
        int retriesCounter = 0;

        while (true)
        {
            try
            {
                args.Proceed();
                return;
            }
            catch (Exception e)
            {
                retriesCounter++;
                if (retriesCounter > this.MaxRetries) throw;

                Console.WriteLine(
                    "Exception during attempt {0} of calling method {1}.{2}: {3}",
                    retriesCounter, args.Method.DeclaringType, args.Method.Name, e.Message);
            }
        }
    }
}



2> OwenP..:

我知道如何做到这一点的唯一方法是使用PostSharp.它会对您的IL进行后期处理,并可以执行您所要求的操作.



3> Ben Scheirma..:

您需要某种面向方面的框架.PostSharp将会这样做,Windsor也是如此.

基本上,他们将您的对象子类化并覆盖此方法......

然后它变成:

//proxy
public override void DoSomeStuff()
{
     if(MethodHasTriggerAttribute)
        Trigger();

     _innerClass.DoSomeStuff();
}

当然这一切对你来说都是隐藏的.您所要做的就是询问Windsor的类型,它将为您进行代理.该属性成为我在温莎的一个(自定义)设施.

推荐阅读
jerry613
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有