एक बहुत ही रोचक सवाल है, मैंने स्थिर जेनेरिक वर्गों का उपयोग करने के लिए कभी भी परीक्षा नहीं दी है, लेकिन कम से कम ऐसा लगता है।
विस्तार विधियों की घोषणा के संदर्भ में, आप केवल एक सामान्य जेनेरिक प्रकार (जैसे IEnumerable<T>
) के लिए एक्सटेंशन विधियों की घोषणा नहीं कर सकते हैं बल्कि समीकरण में टाइप पैरामीटर T
भी ला सकते हैं। अगर हम विभिन्न प्रकार के रूप में IEnumerable<int>
और IEnumerable<string>
का इलाज करने के लिए सहमत हैं, तो यह एक वैचारिक स्तर पर भी समझ में आता है।
एक स्थैतिक जेनेरिक कक्षा में अपनी विस्तार विधियों की घोषणा करने में सक्षम होने से आप IEnumerable<T> where T : IComparable
के लिए सभी एक्सटेंशन विधियों को समूहित करने के बाद, बार-बार अपनी प्रकार की पैरामीटर बाधाओं को दोहरा सकते हैं।
विनिर्देश के अनुसार (उद्धरण वांछित), विस्तार विधियों को केवल स्थैतिक नॉनस्टेड और गैर-सामान्य वर्गों में घोषित किया जा सकता है। पहली दो बाधाओं का कारण काफी स्पष्ट है:
- किसी भी राज्य को नहीं ले सकता क्योंकि यह मिश्रण नहीं है, केवल सिंटेक्टिक चीनी है।
- एक ही व्याख्यात्मक दायरे के रूप में होना चाहिए क्योंकि यह एक्सटेंशन प्रदान करता है।
गैर-सामान्य स्थैतिक वर्गों पर प्रतिबंध मेरे लिए थोड़ा मनमाना लगता है, मैं यहां तकनीकी कारण नहीं आ सकता। लेकिन हो सकता है कि भाषा डिजाइनरों ने आपको लिखित विस्तार विधियों में हतोत्साहित करने का निर्णय लिया जो कि एक सामान्य वर्ग के प्रकार पैरामीटर पर निर्भर करता है जिसके लिए आप विस्तार विधियां प्रदान करना चाहते हैं। इसके बजाय वे चाहते हैं कि आप अपनी विस्तार विधि का वास्तव में सामान्य कार्यान्वयन प्रदान करें, लेकिन अपने सामान्य कार्यान्वयन के अतिरिक्त अपने विस्तार विधियों के अनुकूलित/विशिष्ट (संकलित-समयबद्ध) संस्करण प्रदान करना संभव बनाएं।
मुझे C++ में टेम्पलेट विशेषज्ञता के बारे में याद दिलाता है। संपादित करें: दुर्भाग्यवश यह गलत है, कृपया नीचे मेरे जोड़ देखें।
ठीक है, क्योंकि यह वास्तव में एक दिलचस्प विषय है क्योंकि मैंने कुछ और शोध किया था।वास्तव में एक तकनीकी प्रतिबंध है कि मैं यहां चूक गया।
public static class Test
{
public static void DoSomething<T>(this IEnumerable<T> source)
{
Console.WriteLine("general");
}
public static void DoSomething<T>(this IEnumerable<T> source) where T :IMyInterface
{
Console.WriteLine("specific");
}
}
यह वास्तव में इस संकलक त्रुटि के साथ विफल हो जाएगा: चलो कुछ कोड पर नजर डालते हैं
Type 'ConsoleApplication1.Test' already defines a member called 'DoSomething' with the same parameter types
ठीक है, अगले हम इसे विभाजित करने का प्रयास दो अलग अलग एक्सटेंशन वर्गों में:
public interface IMyInterface { }
public class SomeType : IMyInterface {}
public static class TestSpecific
{
public static void DoSomething<T>(this IEnumerable<T> source) where T : IMyInterface
{
Console.WriteLine("specific");
}
}
public static class TestGeneral
{
public static void DoSomething<T>(this IEnumerable<T> source)
{
Console.WriteLine("general");
}
}
class Program
{
static void Main(string[] args)
{
var general = new List<int>();
var specific = new List<SomeType>();
general.DoSomething();
specific.DoSomething();
Console.ReadLine();
}
}
मेरी शुरुआती छाप के खिलाफ (यह कल रात देर हो चुकी थी), इसके परिणामस्वरूप कॉल साइटों पर अस्पष्टता होगी। इस अस्पष्टता को हल करने के लिए किसी को पारंपरिक तरीके से विस्तार विधि को कॉल करने की आवश्यकता होगी, लेकिन यह हमारे इरादे के खिलाफ है।
तो यह हमें ऐसी स्थिति के साथ छोड़ देता है जहां विस्तार विधियों के संकलन-समयबद्ध जेनेरिक विशेषज्ञता घोषित करना संभव नहीं है। दूसरी तरफ, अभी भी कोई कारण नहीं है कि हम एक विशेष जेनेरिक प्रकार पैरामीटर के लिए विस्तार विधियों केवल घोषित नहीं कर सके। इसलिए उन्हें स्थिर जेनेरिक वर्ग में घोषित करना अच्छा लगेगा।
दूसरी ओर की तरह एक विस्तार विधि लेखन पर:
public static void DoSomething<T>(this IEnumerable<T> source) where T : IMyInterface {}
या
public static void DoSomething(this IEnumerable<IMyInterface> source) {}
सब भी अलग नहीं है और केवल विस्तार पर कॉल साइट बनाम पर एक छोटे से कास्टिंग की आवश्यकता है विधि पक्ष (आप शायद कुछ अनुकूलन लागू करेंगे जो विशिष्ट प्रकार पर निर्भर करता है, इसलिए आपको टी को IMyInterface या किसी भी तरह से डालना होगा)। इसलिए एकमात्र कारण यह है कि मैं फिर से आ सकता हूं, भाषा डिजाइनर केवल सामान्य रूप से सामान्य फैशन में जेनेरिक एक्सटेंशन लिखने में आपको प्रोत्साहित करना चाहते हैं।
कुछ दिलचस्प चीजें यहां हो सकती हैं यदि हम समीकरण में सह/contravariance लेते हैं, जो सी # 4.0 के साथ पेश किए जाने वाले हैं।
@ डैन ब्रायंट, स्थैतिक जेनेरिक कक्षाओं की अनुमति है। केवल विस्तार विधियों वाले वर्गों के लिए नहीं। – Dykam
प्रश्न के अलावा ... आपके पहले उदाहरण में क्यों है। ToArray() को एक्सटेंशन विधि के रूप में परिभाषित किया जा रहा है? यदि यह क्लास SimpleLinkedList क्लास में है, तो निश्चित रूप से आप केवल एक सार्वजनिक टी [] ToArray() विधि को परिभाषित कर सकते हैं। –
शायद कंपेलरों के लेखन को सरल बनाने के लिए (केवल सी # कंपाइलर नहीं) क्योंकि यह जांचने के लिए शर्तों की संख्या को कम करता है। –