मैं यहां क्या चल रहा है, इसका उचित अनुमान लगा सकता हूं , लेकिन यह सब थोड़ा जटिल है :) इसमें ड्राफ्ट की स्थिति में वर्णित अशक्त अवस्था और अशक्त ट्रैकिंग शामिल है । मौलिक रूप से, उस बिंदु पर जहां हम वापस लौटना चाहते हैं, संकलक चेतावनी देगा कि अभिव्यक्ति की स्थिति "शायद शून्य" के बजाय "शायद अशक्त" है।
यह उत्तर कुछ हद तक कथात्मक रूप में है, बजाय इसके कि "यहाँ के निष्कर्ष" ... मुझे आशा है कि यह इस तरह से अधिक उपयोगी है।
मैं खेतों से छुटकारा पाकर उदाहरण को थोड़ा सरल करने जा रहा हूं, और इन दो हस्ताक्षरों में से एक के साथ एक विधि पर विचार करूंगा:
public static string M(string? text)
public static string M(string text)
नीचे दिए गए कार्यान्वयन में मैंने प्रत्येक विधि को एक अलग संख्या दी है ताकि मैं विशिष्ट उदाहरणों का स्पष्ट उल्लेख कर सकूं। यह सभी कार्यान्वयन को एक ही कार्यक्रम में उपस्थित होने की अनुमति देता है।
नीचे वर्णित प्रत्येक मामले में, हम विभिन्न काम करेंगे लेकिन वापस लौटने की कोशिश करेंगे text
- इसलिए यह text
महत्वपूर्ण है।
बिना शर्त वापसी
पहले, चलो इसे सीधे वापस करने का प्रयास करें:
public static string M1(string? text) => text; // Warning
public static string M2(string text) => text; // No warning
अब तक, इतना सरल। विधि की शुरुआत में पैरामीटर की अशक्त स्थिति "शायद अशक्त" है यदि यह प्रकार की है string?
और "शून्य" नहीं है यदि यह प्रकार की है string
।
साधारण सशर्त वापसी
अब if
कथन स्थिति के भीतर अशक्त की जाँच करें । (मैं सशर्त ऑपरेटर का उपयोग करूंगा, जो मेरा मानना है कि इसका एक ही प्रभाव होगा, लेकिन मैं प्रश्न के प्रति चिंतित रहना चाहता था।)
public static string M3(string? text)
{
if (text is null)
{
return "";
}
else
{
return text; // No warning
}
}
public static string M4(string text)
{
if (text is null)
{
return "";
}
else
{
return text; // No warning
}
}
महान, इसलिए यह एक if
बयान के भीतर की तरह दिखता है जहां स्थिति स्वयं अशक्तता की जांच करती है, if
कथन की प्रत्येक शाखा के भीतर चर की स्थिति अलग हो सकती है: else
ब्लॉक के भीतर , राज्य कोड के दोनों टुकड़ों में "शून्य नहीं" है। तो विशेष रूप से, एम 3 में राज्य "शायद अशक्त" से "शून्य नहीं" में बदल जाता है।
स्थानीय चर के साथ सशर्त वापसी
अब उस स्थिति को एक स्थानीय चर पर फहराने की कोशिश करते हैं:
public static string M5(string? text)
{
bool isNull = text is null;
if (isNull)
{
return "";
}
else
{
return text; // Warning
}
}
public static string M6(string text)
{
bool isNull = text is null;
if (isNull)
{
return "";
}
else
{
return text; // Warning
}
}
एम 5 और एम 6 दोनों चेतावनी जारी करते हैं। इसलिए न केवल हमें M5 में "शायद अशक्त" से "नहीं अशक्त" से राज्य परिवर्तन का सकारात्मक प्रभाव नहीं मिलता है (जैसा कि हमने M3 में किया था) ... हम M6 में विपरीत प्रभाव प्राप्त करते हैं , जहां राज्य "से जाता है" अशक्त नहीं "से" शायद अशक्त "। जिसने वास्तव में मुझे चौंका दिया।
तो ऐसा लगता है कि हमने सीखा है कि:
- "स्थानीय चर की गणना कैसे की जाती है" के आसपास तर्क राज्य की जानकारी के प्रचार के लिए उपयोग नहीं किया जाता है। उस पर और बाद में।
- एक शून्य तुलना का परिचय संकलक को चेतावनी दे सकता है कि यह कुछ पहले से सोचा था कि अशक्त सब के बाद शून्य हो सकता है।
एक उपेक्षित तुलना के बाद बिना शर्त वापसी
बिना शर्त वापसी से पहले तुलना शुरू करके उन बुलेट बिंदुओं में से दूसरे को देखें। (इसलिए हम तुलना के परिणाम की पूरी तरह से अनदेखी कर रहे हैं।):
public static string M7(string? text)
{
bool ignored = text is null;
return text; // Warning
}
public static string M8(string text)
{
bool ignored = text is null;
return text; // Warning
}
ध्यान दें कि एम 8 कैसा लगता है, यह एम 2 के बराबर होना चाहिए - दोनों में एक शून्य-शून्य पैरामीटर है जो वे बिना शर्त वापस लौटते हैं - लेकिन अशक्त के साथ तुलना की शुरूआत राज्य को "नहीं अशक्त" से "शायद अशक्त" में बदल देती है। हम इस text
शर्त के आगे डीरेसीफिकेशन का प्रयास करके इसके और प्रमाण प्राप्त कर सकते हैं:
public static string M9(string text)
{
int length1 = text.Length; // No warning
bool ignored = text is null;
int length2 = text.Length; // Warning
return text; // No warning
}
ध्यान दें कि return
बयान में अब चेतावनी कैसे नहीं है: निष्पादित करने के बाद की स्थिति text.Length
"शून्य नहीं है" (क्योंकि यदि हम उस अभिव्यक्ति को सफलतापूर्वक निष्पादित करते हैं, तो यह अशक्त नहीं हो सकता है)। तो text
पैरामीटर अपने प्रकार के कारण "शून्य नहीं" के रूप में शुरू होता है, अशक्त तुलना के कारण "शायद अशक्त" हो जाता है, फिर बाद में "शून्य नहीं" हो जाता है text2.Length
।
क्या तुलना राज्य को प्रभावित करती है?
तो यह एक तुलना है text is null
... क्या तुलना समान प्रभाव है? यहाँ चार और विधियाँ हैं, सभी एक गैर-अशक्त स्ट्रिंग पैरामीटर से शुरू होती हैं:
public static string M10(string text)
{
bool ignored = text == null;
return text; // Warning
}
public static string M11(string text)
{
bool ignored = text is object;
return text; // No warning
}
public static string M12(string text)
{
bool ignored = text is { };
return text; // No warning
}
public static string M13(string text)
{
bool ignored = text != null;
return text; // Warning
}
भले ही x is object
अब यह एक अनुशंसित विकल्प है x != null
, लेकिन उनके पास एक ही प्रभाव नहीं है: केवल शून्य (किसी भी is
, ==
या !=
) के साथ तुलना राज्य को "नहीं अशक्त" से "शायद अशक्त" में बदल देती है।
क्यों फहराने से हालत पर असर पड़ता है?
पहले हमारे पहले बुलेट पॉइंट पर वापस जाकर, M5 और M6 उस स्थिति का ध्यान क्यों नहीं रखते जिसके कारण स्थानीय परिवर्तन हुआ? यह मुझे आश्चर्यचकित नहीं करता है क्योंकि यह दूसरों को आश्चर्यचकित करता है। संकलक और विनिर्देश में तर्क के उस प्रकार का निर्माण बहुत काम है, और अपेक्षाकृत कम लाभ के लिए। यहाँ एक और उदाहरण है कि अशक्तता से कोई लेना देना नहीं है जहाँ कुछ को प्रभावित करने का प्रभाव पड़ता है:
public static int X1()
{
if (true)
{
return 1;
}
}
public static int X2()
{
bool alwaysTrue = true;
if (alwaysTrue)
{
return 1;
}
// Error: not all code paths return a value
}
भले ही हम जानते हैं कि alwaysTrue
यह हमेशा सच होगा, लेकिन यह विनिर्देश में उन आवश्यकताओं को पूरा नहीं करता है if
जो कथन को अनुपलब्ध करने के बाद कोड बनाते हैं , जो कि हमें चाहिए।
यहाँ एक और उदाहरण है, निश्चित असाइनमेंट के आसपास:
public static void X3()
{
string x;
bool condition = DateTime.UtcNow.Year == 2020;
if (condition)
{
x = "It's 2020.";
}
if (!condition)
{
x = "It's not 2020.";
}
// Error: x is not definitely assigned
Console.WriteLine(x);
}
भले ही हम जानते हैं कि कोड उन if
विवरण निकायों में से एक में प्रवेश करेगा , लेकिन उस काम के लिए कुछ भी नहीं है। स्टेटिक विश्लेषण टूल अच्छी तरह से ऐसा करने में सक्षम हो सकता है, लेकिन यह कहने की कोशिश कर रहा है कि भाषा विनिर्देश में एक बुरा विचार होगा, IMO - स्थैतिक विश्लेषण टूल के लिए यह ठीक है कि सभी प्रकार की विधियां हैं जो समय के साथ विकसित हो सकती हैं, लेकिन इतना नहीं एक भाषा विनिर्देश के लिए।