C # में इस स्पष्ट आत्म संदर्भ का उद्देश्य क्या है?


21

मैं अपने एक प्रोजेक्ट में उपयोग के लिए पिरान्हा ( http://piranhacms.org/ ) नामक एक खुले स्रोत का मूल्यांकन कर रहा हूं। मुझे निम्न कोड रोचक और थोड़ा भ्रमित करने वाला लगा, कम से कम मेरे लिए। क्या कुछ मुझे यह समझने में मदद कर सकते हैं कि वर्ग एक ही प्रकार के आधार से क्यों विरासत में मिला है?

public abstract class BasePage<T> : Page<T> where T : BasePage<T>
{
    /// <summary>
    /// Gets/sets the page heading.
    /// </summary>
    [Region(SortOrder = 0)]
    public Regions.PageHeading Heading { get; set; }
}

यदि एक वर्ग को BasePage<T>परिभाषित किया जा रहा है, तो विरासत से क्यों Page<T> where T: BasePage<T>? यह किस विशिष्ट उद्देश्य से कार्य करता है?



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

बस चारों ओर लटकाएं और बंद होने पर इसे फिर से खोलें।
डेविड अरनो

एफ-बाउंडेड पॉलीमॉर्फिज्म की अवधारणा पर पढ़ें :)
आईविंड

1
@ एविंद मैंने वास्तव में किया था। एफ- बाउंडेड
~

जवाबों:


13

क्या कुछ मुझे यह समझने में मदद कर सकते हैं कि वर्ग एक ही प्रकार के आधार से क्यों विरासत में मिला है?

यह नहीं है, यह विरासत में मिला है Page<T>, लेकिन Tखुद को एक प्रकार से पैरामीटर किए जाने के लिए विवश है जो इससे प्राप्त होता है BasePage<T>

यह जानने के लिए कि आपको यह देखना है कि Tवास्तव में टाइप पैरामीटर का उपयोग कैसे किया जाता है। कुछ खुदाई के बाद, जैसा कि आप वंशानुक्रम श्रृंखला को आगे बढ़ाते हैं, आप इस वर्ग पर आएंगे:

( गीथूब )

public class GenericPage<T> : PageBase where T : GenericPage<T>
{
    public bool IsStartPage {
        get { return !ParentId.HasValue && SortOrder == 0; }
    }

    public GenericPage() : base() { }

    public static T Create(IApi api, string typeId = null)
    {
        return api.Pages.Create<T>(typeId);
    }
}

जहां तक ​​मैं देख सकता हूं, जेनेरिक बाधा का एकमात्र उद्देश्य यह सुनिश्चित करना है कि Createविधि कम से कम अमूर्त प्रकार को वापस लौटाए।

यकीन नहीं है कि अगर यह इसके लायक है, हालांकि, लेकिन शायद इसके पीछे कुछ अच्छा कारण है, या यह केवल सुविधा के लिए हो सकता है, या शायद इसके पीछे कोई बहुत अधिक पदार्थ नहीं है और यह सिर्फ एक डाली (बीटीडब्ल्यू, आई) से बचने का एक शानदार तरीका है मैं यह नहीं कह रहा हूँ कि यहाँ मामला है, मैं सिर्फ यह कह रहा हूँ कि लोग कभी-कभी ऐसा करते हैं)।

ध्यान दें कि यह उन्हें प्रतिबिंब से बचने की अनुमति नहीं देता है - उन api.Pagesपृष्ठों का भंडार है जो प्राप्त करता है typeof(T).Name, और इसे विधि के रूप में typeIdपास करता contentService.Createहै ( यहां देखें )।


5

इसका एक सामान्य उपयोग आत्म-प्रकार की अवधारणा से संबंधित है: एक प्रकार का पैरामीटर जो वर्तमान प्रकार का समाधान करता है। मान लीजिए कि आप एक clone()विधि के साथ एक इंटरफ़ेस को परिभाषित करना चाहते हैं । clone()विधि हमेशा वर्ग जिस पर यह कहा जाता था का एक उदाहरण लौट जाना चाहिए। आप उस तरीके को कैसे घोषित करते हैं? एक जेनेरिक प्रणाली में जिसमें आत्म-प्रकार होते हैं, यह आसान है। तुम सिर्फ यह कहते हो कि वह लौट आए self। इसलिए यदि मेरे पास एक वर्ग है Foo, तो क्लोन विधि को वापस करने के लिए घोषित किया जाना चाहिए Foo। जावा में और (सरसरी खोज से) C #, यह एक विकल्प नहीं है। आप इसके बजाय घोषणाओं को देखते हैं जैसे आप इस वर्ग में क्या देखते हैं। यह समझना महत्वपूर्ण है कि यह आत्म-प्रकार के समान नहीं है और इसके द्वारा प्रदान किए गए प्रतिबंध कमजोर हैं। यदि आपके पास एक Fooऔर एक Barवर्ग है जो दोनों से प्राप्त होता हैBasePage, आप कर सकते हैं (अगर मैं गलत नहीं हूँ) फू को परिभाषित करने के लिए परिभाषित किया जाए Bar। यह उपयोगी हो सकता है, लेकिन मुझे लगता है कि आमतौर पर, ज्यादातर समय, यह एक स्व-प्रकार की तरह उपयोग किया जाएगा और यह सिर्फ यह समझा जाता है कि भले ही आप अन्य प्रकारों के साथ घूम सकते हैं और स्थानापन्न कर सकते हैं, यह ऐसा कुछ नहीं है जो आपको करना चाहिए। मैंने इस विचार के साथ बहुत पहले खेला था, लेकिन इस निष्कर्ष पर पहुंचा कि यह जावा जेनरिक की सीमाओं के कारण प्रयास के लायक नहीं था। सी # जेनरिक बेशक पूरी तरह से चित्रित हैं लेकिन ऐसा लगता है कि यह एक ही सीमा है।

दूसरी बार इस दृष्टिकोण का उपयोग तब किया जाता है जब आप ग्राफ़-जैसे प्रकार जैसे कि पेड़ या अन्य पुनरावर्ती संरचनाएँ बना रहे होते हैं। घोषणा प्रकारों को पृष्ठ की आवश्यकताओं को पूरा करने की अनुमति देता है लेकिन आगे प्रकार को परिष्कृत करता है। आप इसे एक पेड़ की संरचना में देख सकते हैं। उदाहरण के लिए कार्यान्वित करने के लिए अनुमति देने के लिए Nodeपरिमाणित किया जा सकता है Nodeताकि यह परिभाषित किया जा सके कि वे केवल किसी भी प्रकार के नोड वाले पेड़ नहीं हैं, लेकिन एक विशिष्ट उप-प्रकार के नोड (आमतौर पर उनके स्वयं के प्रकार।) मुझे लगता है कि यहाँ क्या हो रहा है।


3

उस व्यक्ति के रूप में, जिसने वास्तव में कोड लिखा था, मैं पुष्टि कर सकता हूं कि फ़िलिप सही है और स्व-संदर्भित जेनेरिक वास्तव में बेस क्लास पर टाइप की गई विधि प्रदान करने की सुविधा है।

जैसे वह उल्लेख करता है, अभी भी बहुत कुछ प्रतिबिंब चल रहा है, और अंत में केवल प्रकार का नाम पृष्ठ प्रकार को हल करने के लिए उपयोग किया जाता है। इसका कारण यह है कि आप डायनामिक मॉडल को भी लोड कर सकते हैं, यानी सीएलआर प्रकार तक पहुंच के बिना मॉडल को भौतिक बना सकते हैं जिसने इसे पहले स्थान पर बनाया है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.