2012-04-04 12 views
5

निम्नलिखित वर्ग की कल्पना कीजिए:गतिशील रूप से प्रतिबिंब के माध्यम से संपत्ति गेटर/सेटर उत्पन्न या इसी तरह

public class Settings 
{ 
    [FileBackedProperty("foo.txt")] 
    public string Foo { get; set; } 
} 

मैं ऊपर करने के लिए कुछ इसी तरह लिख सकते हैं और करने में सक्षम होना चाहते हैं settings.Foo फ़ाइल "foo.txt" से पढ़ा और settings.Foo = "bar" "foo.txt" पर लिखें।

जाहिर है यह एक सरलीकृत उदाहरण है और मैं उपरोक्त उत्पादन अनुप्रयोग में नहीं करूँगा, लेकिन अन्य उदाहरण भी हैं, जैसे कि मैं चाहता हूं कि फू को एएसपीनेट सत्र राज्य "foo" में संग्रहीत किया जाए लेकिन मैं थक गया अधिक से अधिक निम्नलिखित कोड लिखने की:

public int Foo 
{ 
    get 
    { 
     if (Session["foo"] != null) 
      return Convert.ToInt32(Session["foo"]); 
     else 
      // Throw an exception or return a default value 
    } 
    set 
    { 
     Session["foo"] = value; 
    } 
} 

(एक बार फिर इस उदाहरण सरलीकृत है और मैं इसके बाद के संस्करण कोड नहीं लिखते थे, वास्तव में मैं झूठ बोल रहा हूँ, मैं ऊपर कोड है और यह refactor करने के लिए काम कर रहा हूँ , इस प्रकार यह प्रश्न)

उपर्युक्त उदाहरण तब तक ठीक है जब तक आपके पास 50 अलग-अलग सत्र मान नहीं होते हैं जिनमें सभी समान तर्क होते हैं। तो क्या कोई है कि मैं दूसरी संपत्ति को पहले जैसा कुछ बदल सकता हूं? (? गुण और प्रतिबिंब, या हो सकता है किसी अन्य विधि का उपयोग करना)

+0

यदि आप विजुअल स्टूडियो का उपयोग कर रहे हैं तो आपको [कोड स्निपेट] (http://msdn.microsoft.com/en-us/library/ms165392%28v=vs.90%29.aspx) पर एक नज़र डालना चाहिए। वे आपको कुछ छोटा टाइप करने, वांछित कोड में विस्तार करने की अनुमति देते हैं और फिर आपको निर्दिष्ट क्षेत्रों में भरने की अनुमति देते हैं। मौजूदा प्रोप के समान, आदि –

+0

@ जोशुआ ड्रेक यह कॉपी/पेस्ट के रूप में उतना ही बुरा लगता है। अगर मैं कार्यान्वयन को बदलना चाहता हूं तो क्या होगा? मुझे अभी भी वापस जाना है और प्रत्येक संपत्ति को व्यक्तिगत रूप से बदलना है। – thelsdj

+0

तो क्या आप रनटाइम पर गुणों को गतिशील रूप से जोड़ना चाहते हैं? क्या आपके पास सभी सर्वर मशीनें हैं, या प्रदर्शन की कम अपेक्षाएं हैं? ऐसा नहीं है कि आप ऐसा नहीं कर सकते हैं, लेकिन मैं इसके खिलाफ सावधानी बरतता हूं। यदि आपके पास रनटाइम पर इसका मतलब नहीं था, तो आपको किसी भी कोड आउटपुट को पुन: उत्पन्न करना होगा। –

उत्तर

1

बहुत बहुत गेटर कोड लिखने से बचना चाहते हैं, एक सहायक विधि लिखें:

public int Foo 
{ 
    get 
    { 
     return GetHelper<int>("foo"); 
    } 
    set 
    { 
     Session["foo"] = value; 
    } 
} 

public T GetHelper<T>(string name, T defaultValue = default(T)) 
{ 
    if (Session[name] != null) 
     return (T)Session[name]; 
    else 
    { 
     return defaultValue; 
    } 
} 

आप गतिशीलता के लिए उपयोग किया है, तो आप एक गतिशील वस्तु का उपयोग कर सकते सत्र रैप करने के लिए:

internal class DynamicSession : DynamicObject 
{ 
    private HttpSessionState_session; 

    public DynamicSession() 
    { 
     _session = HttpContext.Current.Session; 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     if (_session[binder.Name] != null) 
     { 
      result = _session[binder.Name]; 
      return true; 
     } 
     result = null; 
     return false; 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     _session[binder.Name] = value; 
     return true; 
    } 
} 

और तुम तो यह बहुत की तरह उपयोग कर सकते हैं:

dynamic session = new DynamicSession(); 
    //These properties are "magically" put in and taken out of session! 
//get 
int foo = session.Foo; 
//set 
session.Foo = 3; 

एक अंतिम विकल्प Live Templates जैसे रिशेर्पर में बस कोड को बहुत आसान बनाने के लिए कुछ है।

+0

एचएम .. लेकिन यह * लगता है * कुछ ओपी वास्तव में बचने की कोशिश कर रहा है ... – Tigran

+0

@ टिग्रेन हाँ, लेकिन शायद यह संभव नहीं है। उपरोक्त _is_ छोटा और कम डुप्लिकेशन है। ऐसा बुरा लगता है कि जो कुछ मैं चाहता हूं उसे करने का कोई अच्छा तरीका नहीं है क्योंकि यह नकल के एक टन से छुटकारा पाता है। – thelsdj

+0

@thelsdj: मेरा जवाब देखें, आपके लिए एक अच्छा विकल्प हो सकता है, इमो। – Tigran

1

जो आप करने की कोशिश कर रहे हैं उसे "आस्पेक्ट-ओरिएंटेड प्रोग्रामिंग" कहा जाता है और यह कुछ कार्यों के लिए अपेक्षाकृत आम है जहां आवश्यक कोड अन्यथा केवल मामूली परिवर्तनों के साथ डुप्लीकेट किया जाएगा। आपका उदाहरण निश्चित रूप से योग्यता प्राप्त करता है।

मूल विचार निम्नानुसार है; आप एक विशेषता बनाते हैं जिसका उपयोग आप कक्षाओं या वर्ग के सदस्यों को सजाने के लिए कर सकते हैं। विशेषता सीएलआर में एक संदेश पासिंग सिस्टम के लिए "संदर्भ" को परिभाषित करती है जो आपको विधि विधि पर एक विधि इंटरसेप्टर को हुक करने की अनुमति देती है जो इसे कहने पर चलाएगी।

समझें कि इसमें एक महत्वपूर्ण प्रदर्शन हिट शामिल है; गुणों द्वारा सजाए गए सदस्यों के साथ ऑब्जेक्ट मार्शलबीरफॉबजेक्ट या कॉन्टेक्स्टबाउंडऑब्जेक्ट से प्राप्त होना चाहिए; इनमें से किसी एक को रनटाइम के दौरान ऑब्जेक्ट के प्रदर्शन के लिए 10x हिट लगेगा, भले ही आप वास्तव में कोई विशेषता सजाते नहीं हैं। http://www.developerfusion.com/article/5307/aspect-oriented-programming-using-net/3/

तुम भी गतिशील प्रॉक्सी का उपयोग विशेषता सजावट या अन्य प्रतिबिंब आधारित जानकारी के आधार पर "मक्खी पर" वस्तुओं को बनाने के कर सकते हैं:

यहाँ कुछ उदाहरण कोड है। सी # डेवलपर्स के बहुत सारे सामान के पीछे यह तकनीक है, जैसे ओआरएम, आईओसी फ्रेमवर्क इत्यादि।आप मूल रूप से कैसल डायनैमिक प्रॉक्सी जैसे कुछ ऑब्जेक्ट का उपयोग करेंगे जो आपके मूल ऑब्जेक्ट की तरह दिखने वाली ऑब्जेक्ट बनाने के लिए था, लेकिन फ़ाइल-आधारित जनसंख्या/दृढ़ता तर्क वाले गुणों से सजाए गए गुणों की ओवरराइड परिभाषाएं थीं।

3

आपके लिए एक और विकल्प PostSharp का उपयोग कर सकता है। आप विशेषताओं को परिभाषित करते हैं और यह अंतिम कोड में IL इंजेक्ट करता है, इसलिए यह आपके स्रोत कोड को बदलने वाला नहीं है। इसके बुरे और उसके सामान क्या हैं।

यह उत्पाद मुफ़्त नहीं है।

कुछ Getting started युक्तियाँ।

उम्मीद है कि इससे मदद मिलती है।

+0

आप इसका उल्लेख करते हैं कि 'आईएल' इंजेक्ट करता है, क्या यह संकलन समय या एप्लिकेशन स्टार्टअप समय या कुछ है? मुझे लगता है कि PostSharp तब प्रदर्शन समस्याओं के आसपास हो जाता है जो ContextBoundObject का उपयोग कर AOP है? – thelsdj

+0

यह एक संकलन समय है। स्वाभाविक रूप से समस्याओं के बिना कोई भलाई नहीं है :) मुख्य, मैं हस्तक्षेप करता हूं, इमो, यह है कि अंतिम द्विआधारी जो चलता है वह वह नहीं है जिसे आप * अपने * कोड को देखकर उम्मीद करते हैं। स्वाभाविक रूप से, कुछ प्रदर्शन मुद्दे भी हैं, लेकिन ऐसा कुछ है जिसे आपके ठोस कार्यान्वयन पर मापा जाना है। – Tigran

+0

मेरा मतलब है कि यह औद्योगिक वर्ग सॉफ्टवेयर है, इसलिए बस ध्यान देने योग्य है। – Tigran

4

मुझे पता है कि यह नहीं है कि आप (और मुझे भी) की आवश्यकता है; लेकिन यह किसी तीसरे पक्ष की लाइब्रेरी का उपयोग किए बिना निकटतम है। आप & सेट विधियों के लिए तर्क बदल सकते हैं और GetProperty और GetCustomAttributes विधियों के लिए कुछ कैहिंग जोड़ सकते हैं या यदि आपके पास पहले से ही बेस क्लास है तो आप & एक हेल्पर क्लास में स्थिर तरीके से सेट विधियां लिख सकते हैं। फिर नहीं सही जवाब और यह भी एक खराब प्रदर्शन हो सकता है, लेकिन कम से कम यह कोड आप कॉपी और पेस्ट (कम हो जाती है:

नोट: यह गुण आदेश संकलक उन्हें इनलाइन करने को रोकने के लिए आभासी करना महत्वपूर्ण है

public class SampleClass : SessionObject 
{ 
    [Session(Key = "SS_PROP")] 
    public virtual int SampleProperty 
    { 
     get { return get(); } 
     set { set(value); } 
    } 

    [Session(Key = "SS_PROP2")] 
    public virtual string SampleProperty2 
    { 
     get { return get(); } 
     set { set(value); } 
    } 
} 

[AttributeUsage(AttributeTargets.Property)] 
public class SessionAttribute : Attribute 
{ 
    public string Key { get; set; } 
} 

public abstract class SessionObject 
{ 
    Dictionary<string, object> Session = new Dictionary<string, object>(); 

    protected void set(object value) 
    { 
     StackFrame caller = new StackFrame(1); 
     MethodBase method = caller.GetMethod(); 
     string propName = method.Name.Substring(4); 
     Type type = method.ReflectedType; 
     PropertyInfo pi = type.GetProperty(propName); 
     object[] attributes = pi.GetCustomAttributes(typeof(SessionAttribute), true); 
     if (attributes != null && attributes.Length == 1) 
     { 
      SessionAttribute ssAttr = attributes[0] as SessionAttribute; 
      Session[ssAttr.Key] = value; 
     } 
    } 

    protected dynamic get() 
    { 
     StackFrame caller = new StackFrame(1); 
     MethodBase method = caller.GetMethod(); 
     string propName = method.Name.Substring(4); 
     Type type = method.ReflectedType; 
     PropertyInfo pi = type.GetProperty(propName); 
     object[] attributes = pi.GetCustomAttributes(typeof(SessionAttribute), true); 
     if (attributes != null && attributes.Length == 1) 
     { 
      SessionAttribute ssAttr = attributes[0] as SessionAttribute; 
      if (Session.ContainsKey(ssAttr.Key)) 
      { 
       return Session[ssAttr.Key]; 
      } 
     } 
     return default(dynamic); 
    } 
} 
0

तुम भी DynamicProxy nuget package from Castle.Core का उपयोग इस व्यवहार को प्राप्त कर सकते हैं।

आप अपने वर्ग के सभी आभासी संपत्तियों के लिए जाओ करने के लिए कॉल और सेट तरीकों को रोक सकता। हालांकि सभी संपत्ति getters और setters आप संशोधित करना चाहते आभासी होना चाहिए

मैंने यहां एक और पूरा उत्तर प्रदान किया है: https://stackoverflow.com/a/48764825/5103354 और एक गिस्ट here उपलब्ध है।

निम्नलिखित व्यवहार का पालन करना चाहिए:

[Fact] 
    public void SuccessFullyRegisterGetAndSetEvents() 
    { 
     ProxyGenerator generator = new ProxyGenerator(); 
     var tracked = generator.CreateClassProxy<TrackedClass>(new GetSetInterceptor()); 
     tracked.SomeContent = "some content"; 
     Assert.Single(tracked.GetEvents()); 
     var eventAfterSomeContentAssigned = tracked.GetEvents().Last(); 
     Assert.Equal(EventType.Set, eventAfterSomeContentAssigned.EventType); 
     Assert.Equal("some content", eventAfterSomeContentAssigned.Value); 
     Assert.Equal("SomeContent", eventAfterSomeContentAssigned.PropertyInfo.Name); 
     tracked.SomeInt = 1; 
     Assert.Equal(2, tracked.GetEvents().Count); 
     var eventAfterSomeIntAssigned = tracked.GetEvents().Last(); 
     Assert.Equal(EventType.Set, eventAfterSomeContentAssigned.EventType); 
     Assert.Equal(1, eventAfterSomeIntAssigned.Value); 
     Assert.Equal("SomeInt", eventAfterSomeIntAssigned.PropertyInfo.Name); 
     var x = tracked.SomeInt; 
     Assert.Equal(3, tracked.GetEvents().Count); 
     var eventAfterSomeIntAccessed = tracked.GetEvents().Last(); 
     Assert.Equal(EventType.Get, eventAfterSomeIntAccessed.EventType); 
     Assert.Equal(1, eventAfterSomeIntAccessed.Value); 
     Assert.Equal("SomeInt", eventAfterSomeIntAccessed.PropertyInfo.Name); 
    } 

आशा इस मदद करता है।

संबंधित मुद्दे