2009-07-16 20 views
7

सभी ठोस कक्षाओं द्वारा एक अमूर्त कार्य लागू किया जाना चाहिए।मैं सभी व्युत्पन्न कक्षाओं को एक अमूर्त विधि या संपत्ति को लागू करने के लिए कैसे मजबूर कर सकता हूं?

कभी-कभी आप अमूर्त समारोह, ठोस वर्ग की भी डेरिवेटिव लागू करने के लिए सभी व्युत्पन्न वर्गों के लिए मजबूर करना चाहते हैं।

class Base { protected abstract Base Clone(); } 
class Concrete : Base { protected override Base Clone(){...}; } 
class Custom : Concrete {} 

मैं संकलक चाहते हैं प्रोग्रामर उस वर्ग CustomClone() को लागू करने की जरूरत है बताने के लिए। क्या कोई रास्ता है?

+0

जब तक विरासत पेड़ में कुछ ठोस वर्ग सार विधि लागू किया गया है, यही कारण है कि आप एक बच्चे अगर चाहेंगे का उपयोग करता है उस ठोस वर्ग के माता-पिता के कार्यान्वयन पर निर्भर करता है? –

+0

मुझे पार्टी के लिए देर हो चुकी है लेकिन मुझे एक ही समस्या है।मुझे एक 'निजी अमूर्त' क्वालीफायर होना पसंद है जो प्रत्येक व्युत्पन्न वर्ग को कार्य को लागू करने के लिए मजबूर करता है लेकिन क्लैस के कोड को मूल रूप से माता-पिता वर्ग के कार्यान्वयन पर वापस आने से रोकता है। 'क्लोन()' एक अच्छा उदाहरण है। मेरा मामला 'ToString() 'की तरह है। प्रति वर्ग कुछ सामान्य लेकिन विशिष्ट। –

+0

असल में यह अक्सर होता है (या मुझे कुछ याद आ रहा है)। –

उत्तर

12

संकलक को लागू करने के लिए यह संभव नहीं है। ऐसी आवश्यकताओं को लागू करने के लिए आप अपनी खुद की विश्लेषण प्लगइन Gendarme या FxCop पर लिख सकते हैं।

+0

प्लगइन उस मामले के बीच अंतर कैसे करेगा जहां आप सभी डेरिवेटिव्स या केवल तत्काल लोगों की आवश्यकता को मजबूर करना चाहते हैं? –

+0

एक विशेषता सबसे सरल दृष्टिकोण होगी - [MustImplement] या कुछ समान। –

2

आपको लगता है कि लागू करने के लिए Concrete एक अमूर्त वर्ग बनाने के लिए होगा।

+0

लक्ष्य एक बेस क्लास होना है जो विस्तार करना आसान है। आप इस बात पर नियंत्रण नहीं रखते कि लोग आपकी कक्षा का विस्तार कैसे करेंगे। आप भी आसपास नहीं हो सकते हैं। पहला पुरस्कार कोड में आवश्यकता को दस्तावेज करना है जिसे संकलक लागू कर सकता है। –

0

आप प्रतिबिंब का उपयोग रन-टाइम में इस की जाँच करें और निष्पादन बाधित करने के लिए, अपनी लाइब्रेरी के "असभ्य" उपयोगकर्ताओं के लिए कहर नष्ट एक अपवाद फेंक कर सकते हैं। अभिनय की दृष्टि से है कि बहुत समझदारी नहीं है, भले ही आप सभी सत्यापित प्रकार के साथ आधार सार कक्षा में एक स्थिर HashSet <System.Type> संग्रहीत कर सकती है।

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

3

मुझे लगता है कि होगा क्या तुम सच में नहीं है सभी व्युत्पन्न वर्ग की जरूरत सार विधि लागू करने के लिए है, लेकिन आप की तरह अपने डिजाइन में एक कोड गंध का एक सा है यह निश्चित रूप से लगता है।

यदि आपके पास Concrete.Clone() विधि में कोई कार्यक्षमता नहीं है, तो आप अपना 'कंक्रीट' वर्ग सार भी बना सकते हैं (बस नाम बदलना सुनिश्चित करें ;-)। क्लोन() विधि का कोई संदर्भ छोड़ दें।

abstract class Base { protected abstract void Clone(); } 
abstract class Concrete : Base { } 
class Custom : Concrete { protected override void Clone() { /* do something */ } } 

आप Concrete.Clone() विधि में कुछ बुनियादी कार्यक्षमता है, लेकिन एक उच्च स्तर से विस्तृत जानकारी की जरूरत है, तो यह बाहर तोड़ अपने आप सार विधि या संपत्ति इस आपूर्ति करने के लिए एक उच्च स्तर कार्यान्वयन के लिए मजबूर कर में जानकारी। concreate वर्ग या उपयोग आधार वर्ग में

abstract class Base { protected abstract void Clone(); } 

abstract class ConcreteForDatabases : Base 
{ 
    protected abstract string CopyInsertStatemement {get;} 

    protected override void Clone() 
    { 
     // setup db connection & command objects 
     string sql = CopyInsertStatemement; 
     // process the statement 
     // clean up db objects 
    } 
} 

class CustomBusinessThingy : ConcreteForDatabases 
{ 
    protected override string CopyInsertStatemement {get{return "insert myTable(...) select ... from myTable where ...";}} 
} 
+0

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

-2

निकालें कार्यान्वयन

0

मैं निम्नलिखित NUnit परीक्षण कार्यान्वयन की जांच करने के प्रतिबिंब का उपयोग करता है बनाया है। उम्मीद है कि आप आवश्यकतानुसार अनुकूलित कर सकते हैं।

मुझे संदेह है कि यह ओवरलोडेड विधियों को अच्छी तरह से संभाल नहीं पाएगा, लेकिन यह मेरे लिए पर्याप्त है।

(टिप्पणियाँ स्वागत)

/// <summary> 
/// Use on a (possibly abstract) method or property to indicate that all subclasses must provide their own implementation. 
/// 
/// This is stronger than just abstract, as when you have 
/// 
/// A { public abstract void Method()} 
/// B: A { public override void Method(){} } 
/// C: B {} 
/// 
/// C will be marked as an error 
/// </summary> 
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] 
public class AllSubclassesMustOverrideAttribute : Attribute 
{ 

} 

[TestFixture] 
public class AllSubclassesMustOverrideAttributeTest 
{ 
    [Test] 
    public void SubclassesOverride() 
    { 
     var failingClasses = new List<string>(); 

     foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) 
     { 
      try 
      { 
       foreach (var type in assembly.GetTypes()) 
       { 
        foreach (var methodInfo in type.GetMethods().Where(m => m.HasAttributeOfType<AllSubclassesMustOverrideAttribute>())) 
        { 
         foreach (var subClass in type.ThisTypeAndSubClasses()) 
         { 
          var subclassMethod = subClass.GetMethod(methodInfo.Name); 

          if (subclassMethod.DeclaringType != subClass) 
          { 
           failingClasses.Add(string.Format("Class {0} has no override for method {1}", subClass.FullName, methodInfo.Name)); 
          } 
         } 
        } 

        foreach (var propertyInfo in type.GetProperties().Where(p => p.HasAttributeOfType<AllSubclassesMustOverrideAttribute>())) 
        { 
         foreach (var subClass in type.ThisTypeAndSubClasses()) 
         { 
          var subclassProperty = subClass.GetProperty(propertyInfo.Name); 

          if (subclassProperty.DeclaringType != subClass) 
          { 
           failingClasses.Add(string.Format("Class {0} has no override for property {1}", subClass.FullName, propertyInfo.Name)); 
          } 
         } 

        } 
       } 
      } 
      catch (ReflectionTypeLoadException) 
      { 
       // This will happen sometimes when running the tests in the NUnit runner. Ignore. 
      } 
     } 

     if (failingClasses.Any()) 
     { 
      Assert.Fail(string.Join("\n", failingClasses)); 
     } 
    } 
} 

यह निम्न विस्तार तरीकों

public static bool HasAttributeOfType<T>(this ICustomAttributeProvider provider) 
    { 
     return provider.GetCustomAttributes(typeof(T), false).Length > 0; 
    } 

    public static IEnumerable<Type> ThisTypeAndSubClasses(this Type startingType) 
    { 
     var types = new List<Type>(); 
     foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) 
     { 
      try 
      { 
       foreach (var type in assembly.GetTypes()) 
       { 
        if (startingType.IsAssignableFrom(type)) 
        { 
         types.Add(type); 
        } 
       } 
      } 
      catch (ReflectionTypeLoadException) 
      { 
       // Some assembly types are unable to be loaded when running as nunit tests. 
       // Move on to the next assembly 
      } 
     } 
     return types; 
    } 
संबंधित मुद्दे

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