2014-06-20 6 views
12

ठीक है, यह लंबा हो सकता है। मैं दो काम करने कोशिश कर रहा हूँ:पोस्टशर्प पहलुओं का निष्पादन निष्पादन

  • मैं एक वर्ग है कि एक और वर्ग है कि हर कॉल करने के लिए रूट किया जाता है का एक उदाहरण पकड़ कर एक अंतरफलक को लागू करता है करना चाहते हैं।

  • मैं भी सभी विधि कॉल को रोकना और कुछ करना चाहता हूं।

दोनों अपने कामों पर महान प्रदर्शन करते हैं। उन्हें जोड़ना केवल एक निष्पादन आदेश में काम करता है और जैसा कि मर्फी के पास है, यह गलत है (कम से कम मेरे लिए)।

मैं रचना इंजेक्षन करना चाहते हैं पहले ताकि सभी कॉल के अवरोधन भी उन है कि पहले इंजेक्शन थे रोकना होगा।

namespace ConsoleApplication13 
{ 
    using System; 
    using System.Reflection; 

    using PostSharp; 
    using PostSharp.Aspects; 
    using PostSharp.Aspects.Dependencies; 
    using PostSharp.Extensibility; 

    [Serializable] 
    [ProvideAspectRole("COMPOSER")] 
    public sealed class ComposeAspectAttribute : CompositionAspect 
    { 
    [NonSerialized] 
    private readonly Type interfaceType; 

    private readonly Type implementationType; 

    public ComposeAspectAttribute(Type interfaceType, Type implementationType) 
    { 
     this.interfaceType = interfaceType; 
     this.implementationType = implementationType; 
    } 

    // Invoked at build time. We return the interface we want to implement. 
    protected override Type[] GetPublicInterfaces(Type targetType) 
    { 
     return new[] { this.interfaceType }; 
    } 

    // Invoked at run time. 
    public override object CreateImplementationObject(AdviceArgs args) 
    { 
     return Activator.CreateInstance(this.implementationType); 
    } 
    } 

    [Serializable] 
    [ProvideAspectRole("INTERCEPTOR")] 
    [MulticastAttributeUsage(MulticastTargets.Method)] 
    [AspectRoleDependency(AspectDependencyAction.Order, AspectDependencyPosition.After, "COMPOSER")] 
    public sealed class InterceptAspectAttribute : MethodInterceptionAspect 
    { 
    public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo) 
    { 
     base.CompileTimeInitialize(method, aspectInfo); 

     // Warning in VS output 
     Message.Write(method, SeverityType.Warning, "XXX", "Method: " + method.Name); 
    } 

    public override void OnInvoke(MethodInterceptionArgs args) 
    { 
     Console.WriteLine("Intercepted before"); 
     args.Proceed(); 
     Console.WriteLine("Intercepted after"); 
    } 
    } 

    interface ITest 
    { 
    void Call(); 
    } 

    class TestImpl : ITest 
    { 
    public void Call() 
    { 
     Console.WriteLine("CALL remote implemented"); 
    } 
    } 

    [InterceptAspect(AspectPriority = 1)] 
    [ComposeAspect(typeof(ITest), typeof(TestImpl), AspectPriority = 2)] 
    class Test 
    { 
    // this should, after compilation, have all methods of ITest, implemented through an instance of TestImpl, which get intercepted before TestImpl is called 

    public void CallLocalImplementedTest() 
    { 
     Console.WriteLine("CALL local implemented"); 
    } 
    } 


    class Program 
    { 
    static void Main() 
    { 
     var test = new Test(); 

     ITest t = Post.Cast<Test, ITest>(test); 

     Console.WriteLine("TEST #1"); 
     t.Call(); 

     Console.WriteLine("TEST #2"); 
     test.CallLocalImplementedTest(); 

     Console.ReadLine(); 
    } 
    } 
} 

मैं

  • AspectRoleDependency से दो पहलुओं के निष्पादन के आदेश को प्रभावित करने की कोशिश की है, इंटरसेप्टर बनाने पहले

  • AspectPriority चलाने के लिए संगीतकार पर निर्भर करते हैं, यह भी संगीतकार बनाने पहले भागो

परीक्षण हमेशा की

TEST #1 
CALL remote implemented 

TEST #2 
Intercepted before 
CALL local implemented 
Intercepted after 

यह स्पष्ट रूप से काम नहीं करता है उपज। क्या आपके पास कोई सुराग है कि मेरा निष्पादन आदेश क्यों नहीं बदला है? क्या मैंने कुछ गलत किया, क्या मुझे दस्तावेज़ीकरण में कोई जानकारी याद आई? मैं अपनी रचना-इंजेक्शन विधियों को रोकने के लिए क्या कर सकता हूं?

+0

आप भी अपने वांछित परिणाम प्राप्त करने 'TestImpl' वर्ग पर' InterceptAspect' जोड़ने की जरूरत । – nemesv

+0

@nemesv हालांकि यह संभवतः काम करेगा, TestImpl क्लास कभी-कभी मेरी कक्षा नहीं है।मैं एक समाधान पसंद करूंगा जहां मैं testImpl को छोड़ सकता हूं। – nvoigt

+0

वैकल्पिक रूप से आप 'आईटेस्ट' इंटरफ़ेस पर अपने '[इंटरसेप्टएस्पेक्ट (विशेषता इन्टरिटेंस = मल्टीकास्ट इन्हेरिटेंस। मल्टीकास्ट)] डाल सकते हैं। लेकिन यह सबसे दूर है कि आप क्या प्राप्त कर सकते हैं। समस्या यह है कि पोस्टशर्प आईएल को एक चरण में लहराता है और यह केवल 'इंटरसेप्टएस्पेक्ट' को लागू करता है जो संकलन समय पर मौजूद हैं, इसलिए इसे 'कंपोज़एस्पेक्ट' के साथ जोड़े गए नए इंटरफ़ेस कार्यान्वयन को नहीं देखा जाता है। तो जिस प्रकार आप 'कंपोज़एस्पेक्ट' के साथ जोड़ते हैं, उसमें 'इंटरसेप्टएस्पेक्ट' द्वारा प्रदान किए गए लॉगिंग कोड में पहले से ही 'आईटेस्ट' या 'टेस्टआईएमपीएल' वर्ग पर डालने के साथ होना चाहिए। – nemesv

उत्तर

2

वर्तमान पहलुओं और आपके वर्तमान सेटअप के साथ आप अपने वांछित परिणाम को प्राप्त नहीं कर सकते हैं।

समस्या कैसे Postsharp काम में है: यह आईएल एक कदम में लहराते करता है और यह केवल तरीकों जो मूल संकलन समय में उपस्थित तो यह नए इंटरफ़ेस कार्यान्वयन के साथ जोड़ा नहीं देखता हैं InterceptAspect लागू होता है ComposeAspect

इसलिए स्वीकार करने या भूमिका, प्राथमिकताओं या अन्य कॉन्फ़िगरेशन प्रदान करने का कोई आदेश यहां सहायता नहीं करेगा।

एक वैकल्पिक हल इंजेक्शन TestImpl वर्ग पर InterceptAspect जोड़ने के लिए होगा:

[InterceptAspect] 
class TestImpl : ITest 
    { 
    public void Call() 
    { 
     Console.WriteLine("CALL remote implemented"); 
    } 
    } 

इस मामले लॉगिंग तर्क सीधे जोड़ दिया जाएगा TestImpl इसलिए इन विधि प्रवेश में शामिल होंगे जब यह में बना दिया जाएगा में अपने Test कक्षा।

या यदि आप हर कार्यान्वयन चिह्नित नहीं करते आप के साथ इंटरफेस पर ही अपने पहलू रख सकते हैं:

[InterceptAspect(AttributeInheritance = MulticastInheritance.Multicast)] 
interface ITest 
{ 
    void Call(); 
} 
संबंधित मुद्दे