C # /। NET में नहीं के रूप में निशान मापदंडों?


98

क्या कोई साधारण विशेषता या डेटा अनुबंध है जिसे मैं एक फ़ंक्शन पैरामीटर को असाइन कर सकता हूं nullजो C # /। NET में पास होने से रोकता है? आदर्श रूप से यह भी संकलन समय पर जांच करेगा कि यह सुनिश्चित करने के लिए कि शाब्दिक nullका उपयोग कहीं भी नहीं किया जा रहा है और रन-टाइम थ्रो पर ArgumentNullException

वर्तमान में मैं कुछ ऐसा लिख ​​रहा हूं ...

if (null == arg)
  throw new ArgumentNullException("arg");

... हर उस तर्क के लिए, जिसकी मुझे उम्मीद नहीं है null

उसी नोट पर, क्या इसके विपरीत है Nullable<>जिससे निम्नलिखित विफल हो जाएगा:

NonNullable<string> s = null; // throw some kind of exception

7
सी # के हाल के संस्करणों के साथ, "नेमॉफ़ ()" का उपयोग करना बेहतर काम करता है: नए ArgumentNullException (nameof (arg)) फेंकें); इस तरह, यदि आप नाम को
रिफलेक्टर

C # 8 अब अशक्त संदर्भ प्रकारों का समर्थन करता है जो एक संकलक विकल्प है जिसे आप अपनी परियोजना में चालू कर सकते हैं। docs.microsoft.com/en-us/dotnet/csharp/nullable-references
पॉल स्टेगलर

जवाबों:


69

दुर्भाग्य से, संकलन-समय पर कुछ भी उपलब्ध नहीं है।

मेरे पास एक हैकी समाधान है जो मैंने अपने ब्लॉग पर हाल ही में पोस्ट किया है, जिसमें एक नई संरचना और रूपांतरण का उपयोग किया गया है।

.NET 4.0 में कॉन्ट्रैक्ट कॉन्ट्रैक्ट्स के साथ जीवन बहुत अच्छा होगा। वास्तविक भाषा सिंटैक्स और गैर-अशक्तता के आसपास समर्थन करना अभी भी काफी अच्छा होगा, लेकिन कोड अनुबंध बहुत मदद करेगा।

मेरे पास MiscUtil में ThrowIfNull नामक एक विस्तार विधि भी है जो इसे थोड़ा सरल बनाती है।

एक अंतिम बिंदु - " if (null == arg)" के बजाय " " का उपयोग करने का कोई कारण if (arg == null)? मुझे बाद में पढ़ने में आसानी होती है, और समस्या सी में पूर्व हल सी # पर लागू नहीं होती है।


2
> दुर्भाग्य से, संकलन-समय पर कुछ भी उपलब्ध नहीं है। > ...> यह अभी भी वास्तविक भाषा वाक्यविन्यास और मैं सहमत हूँ गैर-अशक्तता के आसपास समर्थन करने के लिए काफी अच्छा होगा। मैं संकलन-समय की त्रुटियों को भी उठाते देखना चाहूंगा।
एंड्रयूजैकसनजेडए

2
@ नहीं, अगर "(arg = null)" काम नहीं करता है तो क्या परिभाषित बूल के लिए एक निहित कास्ट होता है? मैं मानता हूँ कि यह विकृत लग सकता है, लेकिन यह संकलन करता है ...
थॉमस एस। ट्रायस

11
@ ThomasS.Trias: हाँ, कि अविश्वसनीय रूप से अस्पष्ट बढ़त मामले में, संयुक्त गलत वर्तनी, कि कोड के आसपास परीक्षण की एक कमी के साथ संयुक्त वहाँ होने के साथ, आप एक समस्या को रखना होगा। उस बिंदु से मुझे लगता है कि आपके पास बड़ी समस्याएं हैं :)
जॉन स्केट

4
@ जॉन: दी। मुझे लगता है कि मैं अपनी प्यारी योदा की स्थितियों को छोड़ दूंगा। :-)
थॉमस एस। ट्राईस

1
@ सेबैस्टियनमैच: मेरा मानना ​​है कि इसका if (null == x)कारण प्राकृतिक भाषा के मतभेदों के कारण नहीं है । मेरा मानना ​​है कि यह वास्तव में एक अप्रचलित शैली के बारे में है जो सिर्फ उदाहरणों आदि के माध्यम से प्रचारित करता है
जॉन स्कीट

21

मुझे पता है कि मैं इस सवाल के लिए अविश्वसनीय रूप से देर से हूं, लेकिन मुझे लगता है कि उत्तर प्रासंगिक हो जाएगा क्योंकि सी # की नवीनतम प्रमुख पुनरावृत्ति रिलीज के करीब आती है, फिर जारी की जाती है। C # 8.0 में एक बड़ा बदलाव आएगा, C # मानेंगे कि सभी प्रकार को शून्य नहीं माना जाता है।

Mads Torgersen के अनुसार:

समस्या यह है कि अशक्त संदर्भ इतने उपयोगी हैं। C # में, वे हर संदर्भ प्रकार के डिफ़ॉल्ट मान हैं। डिफ़ॉल्ट मान और क्या होगा? एक चर का दूसरा मूल्य क्या होगा, जब तक आप यह तय नहीं कर सकते कि इसे और क्या सौंपा जाए? जब तक आप इसे भरने के लिए चारों ओर नहीं हो जाते, तब तक हम संदर्भों के एक नए तरीके से आवंटित सरणी को कैसे प्रदान कर सकते हैं?

इसके अलावा, कभी-कभी अशक्त और अपने आप में एक समझदार मूल्य होता है। कभी-कभी आप इस तथ्य का प्रतिनिधित्व करना चाहते हैं कि, कहते हैं, एक फ़ील्ड का कोई मूल्य नहीं है। पैरामीटर के लिए "कुछ भी नहीं" पास करना ठीक है। जोर कभी कभी, हालांकि है। और यहाँ समस्या का एक और हिस्सा है: C # जैसी भाषाएं आपको व्यक्त नहीं करती हैं कि यहाँ एक अशक्त एक अच्छा विचार है या नहीं।

इसलिए मैड्स द्वारा उल्लिखित संकल्प है:

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

  2. भाषा में पहले से ही एक धारणा है - और अशक्त मूल्य प्रकार के लिए एक वाक्यविन्यास। दोनों के बीच सामंजस्य भाषा को वैचारिक रूप से आसान और भाषाई रूप से सरल बना देगा।

  3. यह सही लगता है कि जब तक आपने सक्रिय रूप से यह निर्णय नहीं लिया कि आप उन्हें चाहते हैं, तब तक आप अपने या अपने उपभोक्ता को बोझिल मानों से बोझिल नहीं करना चाहिए। अशक्तियाँ, उनकी अनुपस्थिति नहीं, वह चीज होनी चाहिए जिसे आपको स्पष्ट रूप से चुनना है।

वांछित सुविधा का एक उदाहरण:

public class Person
{
     public string Name { get; set; } // Not Null
     public string? Address { get; set; } // May be Null
}

पूर्वावलोकन Visual Studio 2017, 15.5.4+ पूर्वावलोकन के लिए उपलब्ध है।


क्या किसी को पता है कि क्या यह कभी C # 8.0 का हिस्सा था?
ट्रॉयसेवेन

@ ट्रॉयट्वेन हाँ यह है, आपको विज़ुअल स्टूडियो में सेटिंग्स के माध्यम से इसे चुनना होगा।
ग्रेग

@ ट्रॉयसेवन यहाँ इस पर प्रलेखन है। docs.microsoft.com/en-us/dotnet/csharp/nullable-references
ग्रेग

अच्छा है, इसलिए ऐसा लगता है कि काम करने से पहले आपको इसे सक्षम करना होगा, पीछे की संगतता के लिए यह अच्छा है।
ट्रॉयसेवेन

15

मुझे पता है कि यह एक बहुत पुराना सवाल है, लेकिन यह एक यहाँ गायब था:

यदि आप ReSharper / Rider का उपयोग करते हैं तो आप एनोटेट फ्रेमवर्क का उपयोग कर सकते हैं ।

संपादित करें : मुझे इस उत्तर के लिए सिर्फ एक यादृच्छिक -1 मिला है। कोई बात नहीं। बस जागरूक रहें यह अभी भी मान्य है, भले ही यह अब सी # 8.0 + परियोजनाओं के लिए अनुशंसित दृष्टिकोण नहीं है (यह समझने के लिए कि ग्रेग का जवाब क्यों देखें )।


1
दिलचस्प बात यह है कि डिफ़ॉल्ट रूप से अपने संकलित आवेदन JetBrains.Annotations.dll के संदर्भ में नहीं होगा तो आप की जरूरत नहीं है आवेदन के साथ इसे वितरित किया: जेटब्रेन्स एनोटेशन का उपयोग कैसे करें ReSharper निरीक्षण में सुधार करने के
Lu55

9

एंटरप्राइज़ लाइब्रेरी में सत्यापनकर्ताओं की जाँच करें। आप कुछ ऐसा कर सकते हैं:

private MyType _someVariable = TenantType.None;
[NotNullValidator(MessageTemplate = "Some Variable can not be empty")]
public MyType SomeVariable {
    get {
        return _someVariable;
    }
    set {
        _someVariable = value;
    }
}

फिर अपने कोड में जब आप इसे सत्यापित करना चाहते हैं:

Microsoft.Practices.EnterpriseLibrary.Validation.Validator myValidator = ValidationFactory.CreateValidator<MyClass>();

ValidationResults vrInfo = InternalValidator.Validate(myObject);

0

सबसे सुंदर नहीं है लेकिन:

public static bool ContainsNullParameters(object[] methodParams)
{
     return (from o in methodParams where o == null).Count() > 0;
}

आप ContainsNullParameters विधि में भी अधिक रचनात्मक प्राप्त कर सकते हैं:

public static bool ContainsNullParameters(Dictionary<string, object> methodParams, out ArgumentNullException containsNullParameters)
       {
            var nullParams = from o in methodParams
                             where o.Value == null
                             select o;

            bool paramsNull = nullParams.Count() > 0;


            if (paramsNull)
            {
                StringBuilder sb = new StringBuilder();
                foreach (var param in nullParams)
                    sb.Append(param.Key + " is null. ");

                containsNullParameters = new ArgumentNullException(sb.ToString());
            }
            else
                containsNullParameters = null;

            return paramsNull;
        }

बेशक आप एक इंटरसेप्टर या प्रतिबिंब का उपयोग कर सकते हैं, लेकिन इनका पालन करना आसान है


3
इस तरह के प्रश्नों का उपयोग करते हुए बहुत बुरा अभ्यास: return (from o in methodParams where o == null).Count() > 0; उपयोग: return methodParams.Any(o=>o==null);यह बड़े संग्रह में बहुत तेज होगा
यवनोस्तु

अपवाद क्यों पास? सिर्फ इसे क्यों नहीं फेंका?
मार्टिन कैपोडिसी

-4

ठीक है यह उत्तर थोड़ा देर से है, लेकिन यहां बताया गया है कि मैं इसे कैसे हल कर रहा हूं:

public static string Default(this string x)
{
    return x ?? "";
}

इस एक्सर्साइज़ विधि का उपयोग करें फिर आप एक ही चीज़ के रूप में अशक्त और खाली स्ट्रिंग का इलाज कर सकते हैं।

उदाहरण के लिए

if (model.Day.Default() == "")
{
    //.. Do something to handle no Day ..
}

आदर्श नहीं मैं जानता हूं कि आपको हर जगह डिफ़ॉल्ट कॉल करना याद रखना होगा लेकिन यह एक समाधान है।


5
यह (x == null) चेक से बेहतर / आसान कैसे है? या String.IsNotNullOrEmpty फ़ंक्शन।
बटाविया

string.IsNotNullOrEmptyबाईं ओर के बारे में परवाह करने वाली चीनी होने के अलावा वास्तव में बहुत बेहतर नहीं है । अन्य कार्यों (लंबाई, संक्षेपण) आदि में मार्जिन से बेहतर तरीके से खिलाया जा सकता है।
मार्टिन कैपोडिसी

@MartinCapodici इसके अलावा, यह एक भ्रम पैदा करता है कि आप Default()एक नल ( model.Day) पर इंस्टेंस विधि ( ) को कॉल करने के लिए सुरक्षित हैं । मुझे पता है कि विस्तार के तरीकों को अशक्त के खिलाफ जाँच नहीं की जाती है, लेकिन मेरी आँखों को पता नहीं है और उन्होंने पहले से ही ?कोड में कल्पना की है : model?.Day?.Default():)
Alb
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.