दिलचस्प पोस्ट
मैटलप्लिब्ब: विभिन्न तराजू के साथ ओवरले भूखंड? स्लैला में प्रवेश करते समय वापसी का मूल्य कैसे रखा जाए यूएसबी कनेक्टेड एंड्रॉइड मोबाइल डिवाइस से पीसी के स्थानीय होस्ट तक पहुंच एक्सेस प्रतिबंध: आवश्यक पुस्तकालय पर प्रतिबंध के कारण पहुंच योग्य नहीं है .. \ jre \ lib \ rt.jar सिसिरी.स्टैट्स में उपलब्ध सभी वितरण क्या दिखते हैं? कैसे MVC में एक डिफ़ॉल्ट रूट (एक क्षेत्र में) सेट करने के लिए % Op% ऑपरेटर्स आर में क्या मतलब है? उदाहरण के लिए "% in%" एक सरणी को सीमा से बाहर करने से कोई त्रुटि नहीं होती, क्यों? एक परत-सूची तैयार करने योग्य कैसे परिवर्तित करें? ग्रहण में, किसी और एंड्रॉइड प्रोजेक्ट में एंड्रॉइड लाइब्रेरी प्रोजेक्ट को संदर्भित करने में असमर्थ “ “ सबसेट `से बेहतर क्यों है? डेटा की प्रतिलिपि किए बिना मैं ओरेकल तालिका की एक प्रति कैसे बना सकता हूं? क्या पीडीबीबॉक्स में पाठ को सही करना संभव है? जावा में मुख्य धागा बनाम UI थ्रेड क्यों ValueType.GetHashCode () लागू की तरह है?

सी # में सामान्य तर्क की शून्य या डिफ़ॉल्ट तुलना

मेरे पास इस तरह परिभाषित एक सामान्य विधि है:

public void MyMethod<T>(T myArgument) 

पहली चीज जो मैं करना चाहता हूं वह जांचती है कि क्या myArgument का मान उस प्रकार के लिए डिफ़ॉल्ट मान है, कुछ ऐसा:

 if (myArgument == default(T)) 

लेकिन यह संकलन नहीं करता है क्योंकि मैंने इसकी गारंटी नहीं दी है कि टी == ऑपरेटर को लागू करेगा। इसलिए मैंने इसे कोड बदल दिया:

 if (myArgument.Equals(default(T))) 

अब यह संकलित करता है, लेकिन विफल हो जाता है अगर मेरीअर्जमेंट रिक्त है, जो कि मैं किसके लिए परीक्षण कर रहा हूं। मैं इस तरह एक स्पष्ट अशक्त जांच जोड़ सकते हैं:

 if (myArgument == null || myArgument.Equals(default(T))) 

अब यह मुझे बेमानी लगता है ReSharper यह भी सुझाव दे रहा है कि मैं myArgument == नल भाग को myArgument == डिफ़ॉल्ट (टी) में बदलता हूं, जहां मैं शुरू किया था। क्या इस समस्या को हल करने का एक बेहतर तरीका है?

मुझे दोनों संदर्भ प्रकार और मूल्य प्रकारों का समर्थन करने की आवश्यकता है I

वेब के समाधान से एकत्रित समाधान "सी # में सामान्य तर्क की शून्य या डिफ़ॉल्ट तुलना"

मुक्केबाजी से बचने के लिए, समानता के लिए जेनेरिक की तुलना करने का सर्वोत्तम तरीका EqualityComparer<T>.Default साथ है। EqualityComparer<T>.Default यह IEquatable<T> (बिना मुक्केबाजी) के साथ-साथ object.Equals भी object.Equals करता है। object.Equals , और सभी Nullable<T> "उठाए गए" बारीकियों का प्रबंधन करता है अत:

 if(EqualityComparer<T>.Default.Equals(obj, default(T))) { return obj; } 

यह मैच होगा:

  • वर्गों के लिए अशक्त
  • नल के लिए रिक्त (रिक्त) Nullable<T>
  • शून्य / गलत / आदि अन्य स्ट्रेंक्ट्स के लिए

इस बारे में कैसा है:

 if (object.Equals(myArgument, default(T))) { //... } 

static object.Equals() का उपयोग करना। static object.Equals() विधि आपके लिए null जांच करने की आवश्यकता को टालती है। स्पष्ट रूप से object. साथ कॉल योग्यता object. शायद आपके संदर्भ के आधार पर जरूरी नहीं है, लेकिन मैं आमतौर पर कोड को अधिक घुलनशील बनाने के लिए प्रकार के नाम के साथ static कॉल प्रीफिक्स करता हूं।

मैं माइक्रोसॉफ्ट कनेक्ट लेख का पता लगाने में सक्षम था, जो इस मुद्दे पर कुछ विस्तार से चर्चा करता है:

दुर्भाग्यवश, यह व्यवहार डिज़ाइन के अनुसार होता है और ऐसे प्रकार पैरामीटर के साथ उपयोग करने में सक्षम होना आसान उपाय नहीं है जिसमें मूल्य प्रकार हो सकते हैं

यदि प्रकार संदर्भ प्रकार के रूप में जाना जाता है, तो संदर्भ समानता के लिए ऑब्जेक्ट परीक्षण चर पर परिभाषित डिफ़ॉल्ट अधिभार, हालांकि एक प्रकार अपनी कस्टम अधिभार निर्दिष्ट कर सकता है कंपाइलर निर्धारित करता है कि वेरिएबल के स्थिर प्रकार के आधार पर किस अधिभार का उपयोग किया जाए (निर्धारण बहुरूपक नहीं है)। इसलिए, यदि आप सामान्य प्रकार पैरामीटर टी को गैर-मुहरबंद संदर्भ प्रकार (जैसे अपवाद) में बांटने के लिए अपना उदाहरण बदलते हैं, तो संकलक उपयोग करने के लिए विशिष्ट अधिभार निर्धारित कर सकता है और निम्न कोड संकलित करेगा:

 public class Test<T> where T : Exception 

यदि प्रकार मूल्य प्रकार के लिए जाना जाता है, तो उपयोग किए गए सटीक प्रकारों के आधार पर विशिष्ट मूल्य समानता परीक्षण करता है। यहां तुलना में कोई अच्छी "डिफ़ॉल्ट" तुलना नहीं है क्योंकि संदर्भ तुलना मूल्य प्रकारों पर सार्थक नहीं होते हैं और संकलक पता नहीं कर सकते कि किस प्रकार विशिष्ट मूल्य तुलना करना है संकलक ValueType.Equals (ऑब्जेक्ट) के लिए कॉल का उत्सर्जन कर सकता है लेकिन यह विधि प्रतिबिंब का उपयोग करती है और विशिष्ट मूल्य तुलना की तुलना में काफी अक्षम है। इसलिए, भले ही आप टी पर एक मूल्य-प्रकार की बाधा निर्दिष्ट करें, यहां संकलक के लिए यहां कुछ भी उचित नहीं है:

 public class Test<T> where T : struct 

यदि आप प्रस्तुत करते हैं, तो कंपाइलर को यह भी पता नहीं है कि टी एक मान या संदर्भ प्रकार है या नहीं, इसी तरह उत्पन्न होने वाली कोई भी वस्तु नहीं है जो सभी प्रकार के सभी प्रकारों के लिए वैध होगी। एक संदर्भ तुलना मान प्रकारों के लिए मान्य नहीं होगी और कुछ तरह के मूल्य तुलना अप्रत्याशित होंगे संदर्भ प्रकार के लिए जो अधिभार नहीं देते।

यहाँ आप क्या कर सकते हैं …

मैंने मान्य किया है कि इन विधियों दोनों संदर्भ और मान प्रकारों की एक सामान्य तुलना के लिए काम करते हैं:

 object.Equals(param, default(T)) 

या

 EqualityComparer<T>.Default.Equals(param, default(T)) 

"==" ऑपरेटर के साथ तुलना करने के लिए आपको इन तरीकों में से एक का उपयोग करना होगा:

अगर टी के सभी मामलों को किसी ज्ञात आधार वर्ग से प्राप्त किया जाता है, तो आप संकलक को सामान्य प्रकार प्रतिबंधों का उपयोग करने के बारे में बता सकते हैं।

 public void MyMethod<T>(T myArgument) where T : MyBase 

कंपाइलर फिर MyBase पर संचालन करने के लिए कैसे पहचानता है और "ऑपरेटर" == 'को' टी 'और' टी 'त्रुटि के ऑपरेंड्स पर लागू नहीं किया जा सकता है जो अब आप देख रहे हैं।

एक अन्य विकल्प टी को किसी भी प्रकार से प्रतिबंधित करने के लिए होगा जो IComparable लागू करता है

 public void MyMethod<T>(T myArgument) where T : IComparable 

और फिर आईकॉमपरबल इंटरफ़ेस द्वारा परिभाषित तुलना करें विधि का उपयोग करें ।

इसे इस्तेमाल करे:

 if (EqualityComparer<T>.Default.Equals(myArgument, default(T))) 

कि संकलन करना चाहिए, और जो आप चाहते हैं

(संपादित)

मार्क ग्रेवेल का सबसे अच्छा जवाब है, लेकिन मैं एक सरल कोड स्निपेट पोस्ट करना चाहता था जिसने मुझे इसे प्रदर्शित करने के लिए काम किया। बस इसे एक साधारण C # कंसोल ऐप में चलाएं:

 public static class TypeHelper<T> { public static bool IsDefault(T val) { return EqualityComparer<T>.Default.Equals(obj,default(T)); } } static void Main(string[] args) { // value type Console.WriteLine(TypeHelper<int>.IsDefault(1)); //False Console.WriteLine(TypeHelper<int>.IsDefault(0)); // True // reference type Console.WriteLine(TypeHelper<string>.IsDefault("test")); //False Console.WriteLine(TypeHelper<string>.IsDefault(null)); //True //True Console.ReadKey(); } 

एक और बात: VS2008 के साथ कोई एक एक्सटेंशन विधि के रूप में यह कोशिश कर सकता है? मैं यहां 2005 में फंस गया हूं और मुझे यह देखने के लिए उत्सुक है कि क्या इसकी अनुमति होगी।


संपादित करें: यहां यह विस्तार विधि के रूप में कार्य करने के तरीके है:

 using System; using System.Collections.Generic; class Program { static void Main() { // value type Console.WriteLine(1.IsDefault()); Console.WriteLine(0.IsDefault()); // reference type Console.WriteLine("test".IsDefault()); // null must be cast to a type Console.WriteLine(((String)null).IsDefault()); } } // The type cannot be generic public static class TypeHelper { // I made the method generic instead public static bool IsDefault<T>(this T val) { return EqualityComparer<T>.Default.Equals(val, default(T)); } } 

सभी प्रकार के टी को संभालने के लिए, जिसमें टी एक प्रारंभिक प्रकार है, आपको तुलना की दोनों तरीकों में संकलन करना होगा:

  T Get<T>(Func<T> createObject) { T obj = createObject(); if (obj == null || obj.Equals(default(T))) return obj; // .. do a bunch of stuff return obj; } 

यहां एक समस्या होने जा रही है –

यदि आप इसे किसी भी प्रकार के लिए काम करने की अनुमति दे रहे हैं, तो डिफ़ॉल्ट प्रकार (टी) हमेशा संदर्भ प्रकारों के लिए निरर्थक रहेगा, और मूल्य प्रकारों के लिए 0 (या पूर्ण 0 वाला स्ट्रेट) होगा

यह संभवत: आपके बाद के व्यवहार का नहीं है, यद्यपि। यदि आप इसे सामान्य तरीके से काम करना चाहते हैं, तो शायद आपको टी के प्रकार की जांच करने और संदर्भ प्रकारों से भिन्न मान प्रकारों को संभालने के लिए प्रतिबिंब का उपयोग करना होगा।

वैकल्पिक रूप से, आप इस पर एक इंटरफ़ेस बाधा डाल सकते हैं, और इंटरफ़ेस क्लास / स्ट्रैट के डिफ़ॉल्ट के विरुद्ध जांच करने का एक तरीका प्रदान कर सकता है।

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

 public static bool IsNullOrEmpty<T>(T value) { if (IsNull(value)) { return true; } if (value is string) { return string.IsNullOrEmpty(value as string); } return value.Equals(default(T)); } public static bool IsNull<T>(T value) { if (value is ValueType) { return false; } return null == (object)value; } 

IsNull पद्धति में, हम इस तथ्य पर निर्भर हैं कि ValueType ऑब्जेक्ट परिभाषा के द्वारा रिक्त नहीं हो सकते हैं, यदि मान एक वर्ग हो जो ValueType से प्राप्त होता है, हम पहले से जानते हैं कि यह रिक्त नहीं है। दूसरी तरफ, अगर यह मूल्य प्रकार नहीं है तो हम केवल मूल्यों को शून्य के खिलाफ ऑब्जेक्ट के साथ तुलना कर सकते हैं। हम किसी कलाकार को सीधे ऑब्जेक्ट पर जाकर वैल्यू टाइप के खिलाफ चेक से बच सकते हैं, लेकिन इसका मतलब होगा कि एक वैल्यू टाइप बॉक्सिंग होगा जो कि हम शायद कुछ टालना चाहते हैं क्योंकि इसका अर्थ है कि ढेर पर एक नया ऑब्जेक्ट बनाया गया है।

IsNullOrEmpty विधि में, हम एक स्ट्रिंग के विशेष मामले की जांच कर रहे हैं। अन्य सभी प्रकारों के लिए, हम मूल्य की तुलना कर रहे हैं (जो कि पहले से ही पता है कि यह शून्य नहीं है ) इसके मूलभूत मूल्य के विपरीत है जो सभी संदर्भ प्रकारों के लिए शून्य है और मूल्य प्रकार के लिए आमतौर पर शून्य के कुछ रूप हैं (यदि वे अभिन्न हैं)

इन विधियों का उपयोग करते हुए, निम्न कोड के रूप में आप अपेक्षा कर सकते हैं:

 class Program { public class MyClass { public string MyString { get; set; } } static void Main() { int i1 = 1; Test("i1", i1); // False int i2 = 0; Test("i2", i2); // True int? i3 = 2; Test("i3", i3); // False int? i4 = null; Test("i4", i4); // True Console.WriteLine(); string s1 = "hello"; Test("s1", s1); // False string s2 = null; Test("s2", s2); // True string s3 = string.Empty; Test("s3", s3); // True string s4 = ""; Test("s4", s4); // True Console.WriteLine(); MyClass mc1 = new MyClass(); Test("mc1", mc1); // False MyClass mc2 = null; Test("mc2", mc2); // True } public static void Test<T>(string fieldName, T field) { Console.WriteLine(fieldName + ": " + IsNullOrEmpty(field)); } // public static bool IsNullOrEmpty<T>(T value) ... // public static bool IsNull<T>(T value) ... } 

पता नहीं कि यह आपकी आवश्यकताओं के साथ काम करता है या नहीं, लेकिन आप टी को ऐसे टाइप करने के लिए बाधित कर सकते हैं जो आईकॉमपरबल जैसे इंटरफ़ेस लागू करता है और फिर उस अंतरफलक से (जो आईआईआरसी का समर्थन करता है / नलियाँ संभालती है) ComparesTo () विधि का उपयोग करता है :

 public void MyMethod<T>(T myArgument) where T : IComparable ... if (0 == myArgument.ComparesTo(default(T))) 

संभवत: अन्य इंटरफेस हैं जो आप आईक्यूएटीटी आदि के साथ भी इस्तेमाल कर सकते हैं।

@ilitirit:

 public class Class<T> where T : IComparable { public T Value { get; set; } public void MyMethod(T val) { if (Value == val) return; } } 

ऑपरेटर '==' प्रकार 'टी' और 'टी' के ऑपरेंड्स पर लागू नहीं किया जा सकता

मैं बिना किसी स्पष्ट या बिना परीक्षण के बिना ऐसा करने का एक तरीका सोच सकता हूँ।

आप सिस्टम का उपयोग करके एक समाधान तैयार कर सकते हैं। कॉम्परिसन, लेकिन वास्तव में यह कोड की तरह अधिक लाइनों के साथ समाप्त हो रहा है और जटिलता में काफी वृद्धि हुई है।

मुझे लगता है कि आप करीब थे

 if (myArgument.Equals(default(T))) 

अब यह संकलित करता है, लेकिन विफल हो myArgument है अगर myArgument रिक्त है, जो कि मैं किसके लिए परीक्षण कर रहा हूं। मैं इस तरह एक स्पष्ट अशक्त जांच जोड़ सकते हैं:

आपको उस ऑब्जेक्ट को उल्टा करने की जरूरत है जिस पर बराबर एक सुरुचिपूर्ण निरर्थक दृष्टिकोण के लिए बुलाया जा रहा है

 default(T).Equals(myArgument);