ج#:كيفية إنشاء سمة على طريقة تؤدي إلى حدث عند استدعائه؟

StackOverflow https://stackoverflow.com/questions/226420

سؤال

هل هناك طريقة في C# أو .NET بشكل عام لإنشاء سمة على طريقة تقوم بتشغيل حدث عند استدعاء الطريقة؟من الناحية المثالية، سأكون قادرًا على تشغيل الإجراءات المخصصة قبل وبعد استدعاء الطريقة.

أعني شيئا من هذا القبيل:

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

أنا جاهل تمامًا بكيفية القيام بذلك أو إذا كان ذلك ممكنًا على الإطلاق، ولكن System.Diagnostic.ConditionalAttribute قد تفعل شيئا مماثلا في الخلفية.لست متأكدا رغم ذلك.

يحرر:لقد نسيت أن أذكر أنه نظرًا لظروف حالتي المحددة، فإن الأداء ليس مشكلة حقًا.

هل كانت مفيدة؟

المحلول

والطريقة الوحيدة التي يمكنني معرفة كيفية القيام بذلك مع PostSharp . أنه بعد عمليات IL الخاص بك ويمكن أن تفعل أشياء مثل ما طلبت.

نصائح أخرى

يستخدم هذا المفهوم في MVC تطبيقات الويب.

ال صافي الإطار 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 الطريقة داخل myAuthorization يصف قبل الكود داخل Post يتم تنفيذ الطريقة.

إذا عدت false في ال IsAuthorized الطريقة، فإنك تشير إلى عدم منح الترخيص وتنفيذ الطريقة 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.</param>
        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.لاحظ أن هناك إصدارًا سريعًا متاحًا يمكنك استخدامه مجانًا حتى للمشاريع التجارية.

مثال بوستشارب (انظر الرابط أعلاه للحصول على الوصف الكامل):

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

وتحتاج نوعا من إطار الجانب المنحى. سوف PostSharp تفعل ذلك، وسوف وندسور .

وفي الأساس، فإنها فرعية وجوه الخاص بك وتجاوز هذه الطريقة ...

وبعد ذلك يصبح:

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

     _innerClass.DoSomeStuff();
}

وطبعا كل هذا يتم إخفاء لك. كل ما عليك القيام به هو يسأل وندسور لنوع، وانها لن تفعل إنشاء الوكلاء بالنسبة لك. السمة تصبح (حسب الطلب) منشأة أعتقد في وندسور.

ويمكنك استخدام ContextBoundObject وIMessageSink. انظر http://msdn.microsoft.com/nb- رقم / مجلة / cc301356 (أون لنا) .aspx اتصال

وأن حذر من أن هذا النهج له تأثير شديد الأداء مقارنة مع استدعاء أسلوب المباشرة.

وأنا لا أعتقد أن هناك طريقة للقيام بذلك مع سمة فقط، ولكن باستخدام <لأ href = "http://www.codeproject.com/KB/cs/dynamicproxy.aspx" يختلط = "نوفولو noreferrer "> دروس وكيل والتأمل هل يمكن أن يكون فئة التي يعرف لاعتراض التجسيدات من الطبقات التي كنت قد نسبت الأساليب.

وثم فئة الوكيل يمكن أن تؤدي حدث كلما تسمى الطرق المنسوبة.

وسمة يعطي المعلومات، فهي الفوقية. أنا لا أعرف من وسيلة للقيام بذلك مرتجلا، شخص ما من قوة.

هل يمكن أن ننظر في طرق جزئية في. NET التي تسمح لك للقيام ببعض معالجة الحدث خفيفة الوزن. التي تقدمها السنانير والسماح لشخص آخر التعامل مع التنفيذ. إذا لم يتم تنفيذ أسلوب المترجم فقط يتجاهل ذلك.

http://msdn.microsoft.com/en-us/library /wa80x488.aspx

وقد نلقي نظرة على حل الرجل الفقير: انظر نمط الديكور

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top