2009-02-06 14 views
6

यहां मेरी कक्षा का सरलीकृत संस्करण है:क्या बेस क्लास निर्धारित कर सकता है कि व्युत्पन्न वर्ग ने वर्चुअल सदस्य को ओवरराइड किया है या नहीं?

public abstract class Task 
{ 
    private static object LockObject = new object(); 

    protected virtual void UpdateSharedData() { } 
    protected virtual void UpdateNonSharedData() { } 

    public void Method() 
    { 
     lock(LockObject) 
     { 
      UpdateSharedData(); 
     } 
     UpdateNonSharedData(); 
    } 
} 

मैं व्युत्पन्न कक्षाओं से लॉकिंग कोड को छिपाने की कोशिश कर रहा हूं। लेकिन अगर मैं व्युत्पन्न क्लास UpdateSharedData को ओवरराइड करता हूं तो मैं केवल लॉक प्राप्त करना चाहता हूं; यदि ऐसा नहीं होता है, तो मैं नहीं चाहता कि अन्य सभी चल रहे उदाहरणों पर ब्लॉक करने और प्रतीक्षा करने की विधि जो गैर-साझा डेटा अपडेट करने से पहले साझा डेटा अपडेट करें।

तो विधि (ऐसा प्रतीत होता है) विधि के लिए स्पष्ट बात यह जांचना और देखना है कि क्या वर्तमान उदाहरण के अपडेटशेडडेटा के कार्यान्वयन ने बेस क्लास के कार्यान्वयन को ओवरराइड कर दिया है। मुझे यकीन है कि प्रतिबिंब का उपयोग किए बिना यह संभव नहीं है, और शायद ऐसा करने के लिए वांछनीय नहीं है।

मैंने इस पर कुछ कामकाज के बारे में सोचा है, लेकिन वे सभी बहुत अजीब हैं:

  • व्युत्पन्न वर्ग के कन्स्ट्रक्टर सेट की एक संरक्षित बूल संपत्ति जोड़ें, और उस संपत्ति को जांचें कि यह देखने के लिए कि क्या लॉक है जरूरत है। यह व्युत्पन्न कक्षाओं से लॉकिंग कोड छिपाने का एक बहुत ही भयानक काम कर रहा है।
  • UpdateSharedData विधि को एक प्रतिनिधि संपत्ति बनाएं, किसी व्युत्पन्न क्लास को प्रॉपर्टी को अपने कन्स्ट्रक्टर में एक निजी विधि में सेट करें, और केवल प्रतिनिधि लॉक प्राप्त करें यदि प्रतिनिधि शून्य नहीं है। यह बेहतर है, लेकिन यह अभी भी बेकार है।

उत्तर

4

क्या होगा यदि आप एक अमूर्त कार्य और एक IHasSharedData इंटरफेस परिभाषित है, तो विधि में आप जाँच लें कि व्युत्पन्न कार्य करने से पहले IHasSharedData लागू करता है ताला। केवल इंटरफ़ेस को लागू करने वाले वर्गों की प्रतीक्षा की आवश्यकता है। मुझे एहसास है कि यह वास्तविक प्रश्न का उत्तर देने से बचाता है, लेकिन मुझे लगता है कि प्रतिबिंब का उपयोग करने से यह एक क्लीनर समाधान होगा। उम्मीद है कि आपको इंटरफ़ेस के लिए एक बेहतर नाम मिलेगा जो कक्षाओं वास्तव में क्या करता है उससे अधिक निकटता से मेल खाता है।

public interface IHasSharedData 
{ 
    void UpdateSharedData(); 
} 

public abstract class Task 
{ 
    private static object LockObject = new object(); 

    protected virtual void UpdateNonSharedData() { } 

    public void Method() 
    { 
     if (this is IHasSharedData) 
     { 
      lock(LockObject) 
      { 
       UpdateSharedData(); 
      } 
     } 
     UpdateNonSharedData(); 
    } 
} 

public class SharedDataTask : Task, IHasSharedData 
{ 
    public void UpdateSharedData() 
    { 
     ... 
    } 
} 
+0

मुझे अभी एहसास हुआ कि IHasSharedData LOLCats कोड की तरह दिखता है। :-) ICanHazSharedData? – tvanfosson

+0

यह पहली बात थी जो मैंने देखा था! मेरे लिए ऐसा नाम देने का विरोध करना मेरे लिए बहुत कठिन होगा। यह वही जवाब है जिसे मैं फिर भी ढूंढ रहा था। –

4

आप प्रतिबिंब की एक smidge साथ इस चेक कर सकते हैं:

bool IsUpdateSharedDataOverridden() 
{ 
    Type t = this.GetType(); 
    MethodInfo m = subType.GetMethod("UpdateSharedData"); 

    return m.DeclaringType == t && m.GetBaseDefinition().DeclaringType == typeof(Task); 
} 
+0

एम। डीक्लेयरिंग टाइप को सीधे टी से तुलना करना अधिक सही होगा। दो अलग-अलग प्रकारों के लिए एक ही नाम होना बहुत संभव है। – JaredPar

+0

यह भी सही रिपोर्ट करेगा यदि यह विधि को फिर से घोषित करने (ओवरराइड नहीं) करने के लिए "नया" उपयोग करता है। –

+0

अच्छा अंक। तदनुसार तय –

0

असल में, आप के बारे में दो अलग-अलग वस्तुओं बात कर रहे हैं:

public abstract class Task {  
    protected virtual void UpdateNonSharedData() { } 

    public virtual void Method()  
    { 
     UpdateNonSharedData();  
    } 
} 

public abstract class TaskWithSharedData : Task {  
    private static object LockObject = new object();  

    protected virtual void UpdateSharedData() { } 

    public overrides void Method()  
    {  
     lock(LockObject) 
     {   
      UpdateSharedData();  
     } 
     base.Method(); 
    } 
} 

लेकिन, अधिक आदर्श समाधान रणनीति पैटर्न हो जाएगा।

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