मैं C # में एक सामान्य विधि से NULL कैसे लौट सकता हूं?


546

मेरे पास इस (डमी) कोड के साथ एक जेनेरिक विधि है (हाँ, मैं जानता हूँ कि IList की भविष्यवाणी की गई है, लेकिन मेरा कोड IList का उपयोग नहीं कर रहा है, लेकिन कुछ अन्य संग्रह, वैसे भी यह प्रश्न के लिए अप्रासंगिक है ...)

static T FindThing<T>(IList collection, int id) where T : IThing, new()
{
    foreach T thing in collecion
    {
        if (thing.Id == id)
            return thing;
    }
    return null;  // ERROR: Cannot convert null to type parameter 'T' because it could be a value type. Consider using 'default(T)' instead.
}

यह मुझे एक बिल्ड त्रुटि देता है

"पैरामीटर 'T' टाइप करने के लिए अशक्त को परिवर्तित नहीं किया जा सकता है क्योंकि यह एक मूल्य प्रकार हो सकता है। इसके बजाय 'डिफ़ॉल्ट (T)' का उपयोग करने पर विचार करें।"

क्या मैं इस त्रुटि से बच सकता हूँ?


क्या अशक्त संदर्भ प्रकार (C # 8 में) इसका बेहतर समाधान होगा? docs.microsoft.com/en-us/dotnet/csharp/nullable-references रिटर्निंग nullचाहे Tहै Objectया intया char
अलेक्जेंडर -

जवाबों:


968

दो विकल्प:

  • वापसी default(T)आप वापस आ जाएंगे, जिसका मतलब है कि nullअगर टी एक संदर्भ प्रकार (या एक नल मान प्रकार) है, 0के लिए int, '\0'के लिए char, आदि ( डिफ़ॉल्ट मान तालिका (सी # संदर्भ) )
  • टी को प्रतिबंध के साथ एक संदर्भ प्रकार होने के लिए where T : classप्रतिबंधित करें और फिर nullसामान्य रूप से लौटें

3
क्या होगा यदि मेरी वापसी का प्रकार एक एनम एक वर्ग नहीं है? मैं T: enum :(
जस्टिन

1
.NET में एक पूर्णांक प्रकार के आसपास एक एनुम बहुत पतला (और बल्कि टपका हुआ) आवरण होता है। यह सम्मेलन आपके "डिफ़ॉल्ट" एनम मान के लिए शून्य का उपयोग करना है।
माइक चेम्बरलेन

27
मुझे लगता है कि इसके साथ समस्या यह है कि यदि आप कहने के लिए इस सामान्य विधि का उपयोग कर रहे हैं, तो डेटाबेस ऑब्जेक्ट को DbNull से Int में कनवर्ट करें और यह डिफ़ॉल्ट (T) पर लौटता है जहां T एक int है, यह 0. वापस आ जाएगा। यदि यह संख्या है वास्तव में सार्थक है, तो आप उन मामलों में खराब डेटा के आसपास से गुजर रहे होंगे जहां वह क्षेत्र अशक्त था। या एक बेहतर उदाहरण एक DateTime होगा। यदि फ़ील्ड "DateClosed" की तरह कुछ था और इसे शून्य के रूप में लौटा दिया गया था और खाता अभी भी खुला है, तो यह वास्तव में डिफ़ॉल्ट (DateTime) 1/1/0000 को होगा, यह दर्शाता है कि कंप्यूटर का आविष्कार होने से पहले खाता बंद था।
सिनास्टेटिक

21
@ साइनस्टैटिक: तो आप Nullable<int>या Nullable<DateTime>इसके बजाय में परिवर्तित हो जाएगा। यदि आप एक गैर-अशक्त प्रकार का उपयोग करते हैं और एक अशक्त मूल्य का प्रतिनिधित्व करने की आवश्यकता है, तो आप सिर्फ परेशानी के लिए पूछ रहे हैं।
जॉन स्कीट

1
मैं सहमत हूं, मैं इसे ऊपर लाना चाहता था। मुझे लगता है कि मैं जो कर रहा हूं वह MyMethod <T> () की तरह है; यह मानने के लिए कि यह एक अशक्त प्रकार है और MyMethod <T?> (); यह मान लेना एक अशक्त प्रकार है। इसलिए मेरे परिदृश्य में, मैं अशक्त पकड़ने और वहाँ से जाने के लिए एक अस्थायी चर का उपयोग कर सकता था।
सिनास्टेटिक

84
return default(T);

यह लिंक: msdn.microsoft.com/en-us/library/xwth0h0d(VS.80).aspx को समझाना चाहिए कि क्यों।
हार्पर शेल्बी

1
धिक्कार है, मुझे इस कीवर्ड के बारे में पता चलने में बहुत समय बचा होगा - धन्यवाद रिकार्डो!
अना बेट्स

1
मुझे आश्चर्य है कि इससे अधिक वोट नहीं मिले क्योंकि 'डिफ़ॉल्ट' कीवर्ड एक अधिक व्यापक समाधान है, जो संख्यात्मक प्रकारों और संरचनाओं के साथ संयोजन में गैर-संदर्भ प्रकारों के उपयोग की अनुमति देता है। जबकि स्वीकृत उत्तर समस्या को हल करता है (और वास्तव में उपयोगी है), यह बेहतर उत्तर देता है कि वापसी प्रकार को अशक्त / संदर्भ प्रकारों तक कैसे सीमित किया जाए।
स्टीव जैक्सन

33

आप बस अपनी बाधाओं को समायोजित कर सकते हैं:

where T : class

फिर वापस लौटने की अनुमति है।


धन्यवाद। मैं स्वीकृत समाधान के रूप में 2 उत्तर नहीं चुन सकता, इसलिए मैं जॉन स्कीट को चुनता हूं क्योंकि उनके उत्तर के दो समाधान हैं।
edosoft

@ मिगोल यह आपकी आवश्यकताओं पर निर्भर करता है। हो सकता है कि उनके प्रोजेक्ट की आवश्यकता हो IDisposable। हां, ज्यादातर समय ऐसा नहीं होता है। उदाहरण के लिए System.Stringलागू नहीं होता है IDisposable। उत्तर देने वाले को स्पष्ट करना चाहिए था, लेकिन यह उत्तर को गलत नहीं बनाता है। :)
आह्वान

@ मिगोल मुझे इस बात का कोई सुराग नहीं है कि मेरे पास वहां आईडीडिसेप्यूटरी क्यों थी। हटा दिया।
TheSoftwareJedi

13

वर्ग बाधा को अपने सामान्य प्रकार के पहले बाधा के रूप में जोड़ें।

static T FindThing<T>(IList collection, int id) where T : class, IThing, new()

धन्यवाद। मैं स्वीकृत समाधान के रूप में 2 उत्तर नहीं चुन सकता, इसलिए मैं जॉन स्कीट को चुनता हूं क्योंकि उनके उत्तर के दो समाधान हैं।
edosoft

7
  1. अगर आपके पास ऑब्जेक्ट है तो टाइपकास्ट करने की जरूरत है

    return (T)(object)(employee);
  2. यदि आपको अशक्त लौटने की आवश्यकता है।

    return default(T);

हाय user725388, कृपया पहले विकल्प को सत्यापित करें
जोगी जोसेफ जॉर्ज

7

नीचे दो विकल्प दिए गए हैं जिनका आप उपयोग कर सकते हैं

return default(T);

या

where T : class, IThing
 return null;

6

आपका अन्य विकल्प यह होगा कि आप अपनी घोषणा के अंत में इसे शामिल करें:

    where T : class
    where T: IList

इस तरह यह आपको अशक्त लौटने की अनुमति देगा।


यदि दोनों बाधाएं एक ही प्रकार की हैं, तो आप एक बार प्रकार का उल्लेख करते हैं और जैसे अल्पविराम का उपयोग करते हैं where T : class, IList। यदि आपके पास विभिन्न प्रकारों की कमी है, तो आप टोकन को दोहराते हैं where, जैसे कि where TFoo : class where TBar : IList
जेपी स्टिग नीलसन

3

TheSoftwareJedi कार्यों का समाधान,

मूल्य और अशक्त प्रकारों के उपयोग से भी आप इसे संग्रहीत कर सकते हैं:

static T? FindThing<T>(IList collection, int id) where T : struct, IThing
{
    foreach T thing in collecion
    {
        if (thing.Id == id)
            return thing;
    }
    return null;
}

1

त्रुटि की सिफारिश ... और या तो उपयोगकर्ता लो default(T)या new T

यदि आप उस मार्ग पर जाते हैं तो यह सुनिश्चित करने के लिए आपको अपने कोड में एक तुलना जोड़ना होगा।

अन्यथा, संभावित रूप से "मैच पाया" के लिए एक आउटपुट पैरामीटर पर विचार करें।


1

यहाँ Nullable Enum रिटर्न मान के लिए एक कार्य उदाहरण दिया गया है:

public static TEnum? ParseOptional<TEnum>(this string value) where TEnum : struct
{
    return value == null ? (TEnum?)null : (TEnum) Enum.Parse(typeof(TEnum), value);
}

C # 7.3 (मई 2018) के बाद से, आप बाधा को सुधार सकते हैं where TEnum : struct, Enum। यह सुनिश्चित करता है कि एक कॉलर गलती से एक मूल्य प्रकार की आपूर्ति नहीं करता है जो कि एक एनम (जैसे intया क DateTime) नहीं है।
जेपी स्टिग नीलसन

0

ऊपर प्रस्तुत 2 उत्तरों का एक अन्य विकल्प। यदि आप अपने रिटर्न प्रकार को बदल देते हैं object, तो आप वापस लौट सकते हैं null, जबकि उसी समय में नॉन-नेल रिटर्न डाल सकते हैं।

static object FindThing<T>(IList collection, int id)
{
    foreach T thing in collecion
    {
        if (thing.Id == id)
            return (T) thing;
    }
    return null;  // allowed now
}

डाउनसाइड: इसके लिए रिटर्न ऑब्जेक्ट (गैर-अशक्त स्थिति में) को डालने के लिए विधि के कॉलर की आवश्यकता होगी, जिसका अर्थ है बॉक्सिंग -> कम प्रदर्शन। क्या मैं सही हू?
Charharpest

0

पूर्णता के लिए, यह जानना अच्छा है कि आप भी ऐसा कर सकते हैं:

return default;

यह जैसा है वैसा ही लौटता है return default(T);


0

मेरे लिए यह जैसा है वैसा ही काम करता है। समस्या कहां है?

public static T FindThing<T>(this IList collection, int id) where T : IThing, new()
{
    foreach (T thing in collection)
    {
        if (thing.Id == id)
            return thing;
        }
    }

    return null; //work
    return (T)null; //work
    return null as T; //work
    return default(T); //work


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