Enum पर T प्रतिबंध के साथ जेनेरिक विधि: C# के अंतर्गत

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

Enum पर T प्रतिबंध के साथ जेनेरिक विधि: यह अंतर्गत कैसे काम करता है

\n\n

कल्पना करें: आप C# में लिख रहे हैं और एक सार्वभौमिक विधि बनाना चाहते हैं जो किसी भी एनुम (Enum) को स्वीकार करे। आसान लगता है? लेकिन यदि आपने कभी public void DoSomething<T>() where T : Enum लिखने की कोशिश की है, तो आप जानते हैं — कंपाइलर एक त्रुटि देता है। C# 7.3 से पहले यह असंभव था। और बाद में — यह संभव हो गया, लेकिन बारीकियों के साथ। आइए समझते हैं कि यह अंतर्गत कैसे काम करता है, और यह Stack Overflow पर सबसे लोकप्रिय विषयों में से एक क्यों है।

\n\n

यह लेख केवल दस्तावेज़ीकरण का शुष्क पुनर्कथन नहीं है। हम गहराई में जाएंगे: IL-कोड से लेकर ReSharper अनुशंसाओं तक। चलिए शुरू करते हैं!

\n\n

सीधे where T : Enum क्यों नहीं लिख सकते थे?

\n\n

लंबे समय तक, C# ने जेनेरिक-पैरामीटर के लिए प्रतिबंध के रूप में Enum या Delegate के उपयोग पर प्रतिबंध लगाया। क्यों? क्योंकि कंपाइलर को यह गारंटी देनी होती थी कि प्रकार T या तो मान प्रकार (struct) है या संदर्भ प्रकार (class) है। Enum एक विशेष संरचनात्मक प्रकार है, जो System.Enum से विरासत प्राप्त करता है। लेकिन C# के प्रकार प्रणाली में, यह सरल नियमों में फिट नहीं बैठता था:

\n\n
    \n
  • Enum एक struct है, लेकिन कोई भी struct नहीं।
  • \n
  • Enum ValueType से विरासत प्राप्त करता है, लेकिन कंपाइलर where T : System.Enum के उपयोग की अनुमति नहीं देता था।
  • \n
  • where T : struct, Enum लिखने का प्रयास भी काम नहीं करता था।
  • \n
\n\n

डेवलपर्स अस्थायी समाधानों का सहारा लेते थे: runtime में typeof(T).IsEnum के माध्यम से जाँच या रिफ्लेक्शन का उपयोग। लेकिन इससे सारा प्रदर्शन और प्रकार सुरक्षा समाप्त हो जाती थी।

\n\n

C# 7.3: लंबे समय से प्रतीक्षित समाधान

\n\n

C# 7.3 और .NET Core 2.0 / .NET Framework 4.8 से शुरू करके, यह लिखना संभव हो गया:

\n\n
public static string GetEnumName<T>(T value) where T : Enum\n{\n    return Enum.GetName(typeof(T), value);\n}\n
\n\n

अब कंपाइलर समझता है: T एक एनुम है। लेकिन यह वास्तव में कैसे करता है? आइए अंतर्गत देखें।

\n\n

IL-कोड में क्या होता है?

\n\n

जब आप where T : Enum लिखते हैं, तो कंपाइलर Enum.HasFlag, Enum.GetName आदि जैसी विधियों के लिए एक विशेष constrained call उत्पन्न करता है। बॉक्सिंग या रिफ्लेक्शन का उपयोग करने के बजाय, JIT-कंपाइलर विशिष्ट प्रकार T को जानते हुए एक सीधा कॉल स्थिर विधि में डाल सकता है।

\n\n

उपरोक्त विधि के लिए IL-कोड का उदाहरण:

\n\n
.method public hidebysig static \n    string GetEnumName<([mscorlib]System.Enum) T>(!!0 value) cil managed\n{\n    // constrained प्रीफिक्स के साथ Enum.GetName का कॉल\n    call string [mscorlib]System.Enum::GetName(class [mscorlib]System.Type, object)\n}\n
\n\n

विशेषता ([mscorlib]System.Enum) T पर ध्यान दें। यही नया प्रतिबंध है। JIT इसे देखता है और जानता है कि T एक enum है, और इसलिए GetName में value पास करते समय बॉक्सिंग से बचा जा सकता है।

\n\n

व्यवहार में Enum के साथ जेनेरिक विधि का उपयोग कैसे करें?

\n\n

आइए एक उपयोगी उदाहरण बनाएं: केस-असंवेदनशीलता के समर्थन के साथ किसी भी एनुम में स्ट्रिंग को पार्स करने की विधि।

\n\n
public static T ParseEnum<T>(string value, bool ignoreCase = true) where T : Enum\n{\n    if (string.IsNullOrWhiteSpace(value))\n        throw new ArgumentException("Value cannot be null or empty.", nameof(value));\n\n    if (!Enum.TryParse(typeof(T), value, ignoreCase, out object? result))\n        throw new ArgumentException($"'{value}' is not a valid value for enum {typeof(T).Name}.");\n\n    return (T)result;\n}\n
\n\n

महत्वपूर्ण: इस तथ्य के बावजूद कि T एक Enum है, कास्टिंग (T)result को अभी भी स्पष्ट कास्टिंग की आवश्यकता है। ऐसा इसलिए है क्योंकि runtime में object प्रकार जेनेरिक-पैरामीटर के बारे में नहीं जानता है। लेकिन कंपाइलर गारंटी देता है कि T एक enum है, इसलिए कास्टिंग सुरक्षित है।

\n\n

Enum.TryParse<T> के साथ अधिक सुरुचिपूर्ण विकल्प

\n\n

.NET 5 से शुरू करके, एक ओवरलोड उपलब्ध हुआ

ब्लॉग

पुस्तक अनुशंसाएँ