मैं एक पैरामीटर को Guid.Empty में C # कैसे डिफ़ॉल्ट कर सकता हूं?


178

मैं कहना चाहता हूँ:

public void Problem(Guid optional = Guid.Empty)
{
}

लेकिन कंपाइलर को शिकायत है कि Guid.Empty एक संकलन समय स्थिर नहीं है।

जैसा कि मैं एपीआई का उपयोग करने की इच्छा नहीं बदल सकता हूं:

 Nullable<Guid>


Nullable<Guid> optional = null(या अधिक कठिन Guid? optional = null) पर स्विच करने में क्या गलत है ? वर्तमान में इसके लिए पारित किए गए कोई भी मार्गदर्शक बिना किसी भी कोड परिवर्तन के बिना किसी भी तरह के जोर-जबरदस्ती करेंगे।
एनएच।

जवाबों:


235

उपाय

आप new Guid()इसके बजाय उपयोग कर सकते हैं

public void Problem(Guid optional = new Guid())
{
  // when called without parameters this will be true
  var guidIsEmpty = optional == Guid.Empty;
}

आप भी उपयोग कर सकते हैं default(Guid)

default(Guid)यह भी बिल्कुल उसी तरह काम करेगा new Guid()

क्योंकि गाइड एक वैल्यू टाइप है न कि रेफरेंस टाइप, इसलिए, उदाहरण के लिए default(Guid)बराबर नहीं है null, इसके बजाय, यह डिफॉल्ट कंस्ट्रक्टर को कॉल करने के बराबर है।

जिसका अर्थ है कि यह:

public void Problem(Guid optional = default(Guid))
{
  // when called without parameters this will be true
  var guidIsEmpty = optional == Guid.Empty;
}

यह मूल उदाहरण के समान ही है।

व्याख्या

Guid.Emptyकाम क्यों नहीं किया?

आप त्रुटि प्राप्त कर रहे हैं इसका कारण Emptyयह है:

public static readonly Guid Empty;

तो, यह एक वैरिएबल है, न कि एक स्थिर (जैसा static readonlyनहीं है const)। कंपाइलर में केवल कंपाइलर-ज्ञात मान हो सकते हैं क्योंकि विधि पैरामीटर डिफ़ॉल्ट मान (रनटाइम-ओनली-ज्ञात नहीं)।

मूल कारण यह है कि उदाहरण के विपरीत, आपके पास कोई constभी नहीं हो सकता है । यदि आप इसे आजमाते हैं, तो यह संकलन नहीं करेगा।structenum

एक बार और कारण यह है कि structएक आदिम प्रकार नहीं है।
.NET में सभी आदिम प्रकारों की सूची के लिए http://msdn.microsoft.com/en-gb/library/system.typecode.aspx
( enumआमतौर पर विरासत में मिला नोट int, जो एक आदिम है) देखें

लेकिन new Guid()एक स्थिर भी नहीं है!

मैं यह नहीं कह रहा हूं कि इसे एक निरंतरता की जरूरत है। इसे कुछ ऐसा चाहिए जो संकलन समय में तय किया जा सके। Emptyएक क्षेत्र है, इसलिए, यह संकलित समय में ज्ञात नहीं है (केवल रन समय के बहुत शुरुआत में)।

डिफ़ॉल्ट पैरामीटर मान को संकलित-समय पर जाना चाहिए, जो एक constमान हो सकता है , या C # सुविधा का उपयोग करके परिभाषित कुछ ऐसा हो सकता है जो संकलन समय पर मूल्य ज्ञात करता है, जैसे ( default(Guid)या new Guid()जो संकलन समय पर संकलित करने का निर्णय लिया गया है structक्योंकि आप structकंस्ट्रक्टर को संशोधित नहीं कर सकते हैं कोड)।

जब आप प्रदान defaultया newआसानी से कर सकते हैं, तो आप एक प्रदान नहीं कर सकते const(क्योंकि यह एक आदिम प्रकार नहीं है या enumजैसा कि ऊपर बताया गया है)। तो, फिर से, यह नहीं कह रहा है कि वैकल्पिक पैरामीटर को स्वयं एक स्थिर, लेकिन संकलक ज्ञात मूल्य की आवश्यकता है।


5
ठीक है, इसे एक सामान्य स्थिर अभिव्यक्ति की आवश्यकता नहीं है - new Guid()उदाहरण के लिए एक स्थिर अभिव्यक्ति नहीं है। सी # कल्पना काफी स्पष्ट रूप से परिभाषित करती है, जिसमें अनुमति दी जाती है, जिसमें स्थिरांक तक सीमित नहीं है। (बस स्पष्ट होने के लिए, यह प्रभावी रूप से एक संकलन समय स्थिर है, सिर्फ सी # कल्पना शर्तों में "स्थिर अभिव्यक्ति" नहीं है)।
जॉन स्कीट

3
मेरे उत्तर में हिस्सा स्पष्टीकरण पढ़ें । इस भाग का उत्तर देने के लिए जोड़ा गया।
Meligy

अच्छा स्पष्टीकरण। धन्यवाद!
दरियाल

आप केवल defaultआजकल का उपयोग कर सकते हैं :)
जोशित

151

Guid.Emptyके बराबर है new Guid(), जो के बराबर है default(Guid)। तो आप उपयोग कर सकते हैं:

public void Problem(Guid optional = default(Guid))

या

public void Problem(Guid optional = new Guid())

ध्यान दें कि new Foo()मूल्य तभी लागू होता है जब:

  • आप वास्तव में कॉल कर रहे हैं parameterless निर्माता
  • Foo एक मूल्य प्रकार है

दूसरे शब्दों में, जब कंपाइलर जानता है कि यह वास्तव में केवल प्रकार के लिए डिफ़ॉल्ट मान है :)

(दिलचस्प बात यह है कि मैं 99.9% सुनिश्चित हूं कि यह आपके द्वारा बनाए गए किसी भी कस्टम कंस्ट्रक्टर को कॉल नहीं करेगाnew Foo() । आप इस तरह के एक निर्माता को C # में वैल्यू टाइप में नहीं बना सकते, लेकिन आप IL में ऐसा कर सकते हैं।)

आप किसी भी प्रकार के default(Foo)विकल्प का उपयोग कर सकते हैं ।


अब कंपाइलर एरर मैसेज मुझे यह क्यों नहीं बताता है, कम्पलेंट गाइड.मिशन के मामले की जाँच कर सकता है और अधिक उपयोगी मैसेज दे सकता है।
इयान रिंगरोज

4
@ इयान रिंगरोज: मुझे नहीं लगता कि कंपाइलर के पास सामान्य रूप से टाइप-विशिष्ट संदेश होने चाहिए, ईमानदार होने के लिए।
जॉन स्कीट

2
हर बार किसी विधि को डिफ़ॉल्ट करने के लिए एक पैरामीटर सेट करना एक नई वस्तु बनाता है जिसे पीएचपी में विधि कहा जाता है; लेकिन केवल पायथन में पूरे कार्यक्रम के लिए एक वस्तु बनाता है । वास्तव में, मैं इसे पायथन के बहुत कम डिज़ाइन दोषों में से एक मानता हूं । मुझे कुछ हद तक ख़ुशी है कि C # (और VB.Net) ने डिफ़ॉल्ट ऑब्जेक्ट्स में नई वस्तुओं को अस्वीकार करने से इस मुद्दे को टाल दिया ... हालांकि कई बार ऐसा भी होता है जहाँ PHP में यह क्षमता वास्तव में अच्छी है।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

1
क्या कारण हो सकता है कि यह वही काम ASP.NET MVC नियंत्रक कार्रवाई में काम नहीं करेगा? अन्य सभी वैकल्पिक पैरामीटर काम करते हैं (int, string) लेकिन यह GUID के लिए काम नहीं करता है, "सर्वर त्रुटि '/' अनुप्रयोग में कहता है। पैरामीटर डिक्शनरी में पैरामीटर के लिए एक अशक्त प्रविष्टि है, जो 'अशक्त प्रकार' की श्रेणी 'श्रेणी' के लिए है। System.Guid '..' कोड दोनों विशिष्टताओं (डिफ़ॉल्ट (गाइड)) और नए गाइड () के साथ ठीक संकलित करता है, लेकिन यह त्रुटि जारी करता है।
घोड़ी

@ मारे: मुझे नहीं पता, मुझे डर है। एक अन्य विकल्प Nullable<Guid>संभावित रूप से उपयोग करना होगा ।
जॉन स्कीट

18

क्या आप उपयोग नहीं कर सकते:

default ( Guid ) ?


1
संख्या Operator '??' cannot be applied to operands of type 'System.Guid' and 'System.Guid'
पुनरावर्ती

4
क्षमा करें, मेरा मतलब नहीं था ?? एक ऑपरेटर के रूप में, लेकिन एक प्रश्न चिह्न पर जोर देने के रूप में - मैं संपादित करूँगा!
निक

9

स्वीकृत उत्तर ASP.NET MVC में काम नहीं करता है, और इस रन-टाइम त्रुटि का कारण बनता है:

[ArgumentException: The parameters dictionary contains a null entry for parameter 'optional' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult Problem(System.Guid)' ....

इसके बजाय, आप निम्न कार्य कर सकते हैं:

public void Problem(Guid? optional)
{
    if (optional == null)
    {
        optional = new Guid();
    }
}

मैं नीचे मतदान का कारण देखता हूं: यह प्रश्न निर्दिष्ट करता है कि एपीआई को अशक्त <गाइड> का उपयोग करने के लिए नहीं बदला जा सकता है
माजिक्स

जब तक आप खाली गाइड मान के साथ परमार्थक "वैकल्पिक" को स्पष्ट रूप से निर्दिष्ट नहीं करना चाहते, मुझे लगता है कि यह वैकल्पिक गाइड के वैकल्पिक पैरामीटर को परिभाषित करने का सबसे स्वाभाविक तरीका है।
गोंजालो मेन्डेज़

4

संकलक काफी सही है; Guid.Emptyएक संकलन-समय स्थिर नहीं है। आप इस तरह से एक विधि अधिभार बनाने की कोशिश कर सकते हैं:

public void Problem()
{
    Problem(Guid.Empty);
}

मैंने कहा कि मैं एपीआई को बदलना नहीं चाहता था, जिस विधि से मैं वश में करने की कोशिश कर रहा हूं वह 10 पार हो गई है!
इयान रिंगरोज

@ रिंग रिंगरोज़, हालांकि मैं Guid x = default(Guid)समाधान के रूप में सहमत हूं , याद रखें कि एक अन्य फ़ंक्शन अधिभार जोड़ने से एपीआई को वैकल्पिक तर्क जोड़ने की तुलना में किसी भी अधिक जटिल नहीं होता है। यह वास्तव में वैसे भी एक वैकल्पिक तर्क क्या है।
दस

@tenfour, इसे 10 वैकल्पिक parms के समान करने के लिए कई नए फ़ंक्शन ओवरलोड होने होंगे!
इयान रिंगरोज

यदि आपके पास एक सार्वजनिक कार्य है जिसे दस मापदंडों से अधिक की आवश्यकता होती है, तो शायद एक भी तर्क को वैकल्पिक बनाना वास्तव में ठीक नहीं है ... इसके अलावा, मूल प्रश्न को देखते हुए, आप वास्तव में कहते हैं कि आप "बदलना नहीं चाहते" एपीआई "(और दसफोर की तरह, स्पष्ट अधिभार और एक वैकल्पिक तर्क के बीच अंतर कम से कम व्यवहार में है) लेकिन पैरामीटर सूची के इस तरह के राक्षस होने के सवाल में कोई उल्लेख नहीं है।
एक CVn

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