डीप नल चेकिंग, क्या कोई बेहतर तरीका है?


130

नोट: यह सवाल पेश किए जाने से पहले पूछा गया था.? सी में ऑपरेटर # 6 / विजुअल स्टूडियो 2015

हम सब वहाँ रहे हैं, हमारे पास केक की तरह कुछ गहरी संपत्ति है। फ़ॉर्स्टिंग।बेरीज़। लोडर जिसे हमें जांचना होगा कि क्या यह अशक्त है तो कोई अपवाद नहीं है। करने का तरीका यह है कि यदि कथन है तो एक शॉर्ट-सर्कुलेटिंग का उपयोग करें

if (cake != null && cake.frosting != null && cake.frosting.berries != null) ...

यह बिल्कुल सुरुचिपूर्ण नहीं है, और शायद पूरी श्रृंखला की जांच करने का एक आसान तरीका होना चाहिए और देखें कि क्या यह अशक्त चर / संपत्ति के खिलाफ आता है।

क्या कुछ विस्तार विधि का उपयोग करना संभव है या क्या यह एक भाषा सुविधा होगी, या यह सिर्फ एक बुरा विचार है?


3
मैंने उसके लिए बहुत बार कामना की है - लेकिन जो भी विचार आए हैं वे वास्तविक समस्या से भी बदतर थे।
पियरचेन

सभी उत्तरों के लिए धन्यवाद और यह देखने के लिए दिलचस्प है कि अन्य लोगों के विचार समान हैं। मैं सोच रहा था कि मैं इसे कैसे हल करना चाहूंगा और हालांकि एरिक का समाधान अच्छा है, मुझे लगता है कि मुझे बस कुछ इस तरह लिखना होगा अगर (IsNull (abc)), या अगर (IsNotNull (abc)) लेकिन शायद यह सिर्फ मेरे स्वाद के लिए है :)
होमड

जब आप फ्रॉस्टिंग को तुरंत करते हैं, तो इसमें जामुन की एक संपत्ति होती है, इसलिए आपके निर्माता में उस बिंदु पर, क्या आप केवल फ्रॉस्टिंग को बता सकते हैं कि जब भी खाली (शून्य-शून्य) जामुन बनाने के लिए उकसाया जाता है? और जब भी जामुन संशोधित ठंढा होता है क्या मूल्य की जांच करता है ????
डॉग चैंबरलेन

कुछ हद तक संबंधित, कुछ तकनीकें यहां मुझे "गहरी नलियों" की समस्या के लिए बेहतर लगीं, जिन्हें मैं पाने की कोशिश कर रहा था। stackoverflow.com/questions/818642/…
एरॉनएलएस

जवाबों:


223

हमने एक नया ऑपरेशन जोड़ने पर विचार किया है "?" जिस भाषा के शब्दार्थ को आप चाहते हैं। (और इसे अब जोड़ दिया गया है; नीचे देखें।) यही है, आप कहेंगे

cake?.frosting?.berries?.loader

और कंपाइलर आपके लिए सभी शॉर्ट-सर्किटिंग चेक उत्पन्न करेगा।

इसने C # 4 के लिए बार नहीं बनाया। शायद भाषा के भविष्य के काल्पनिक संस्करण के लिए।

अद्यतन (2014):?. ऑपरेटर अब है की योजना बनाई अगले रोसलिन संकलक जारी करने के लिए। ध्यान दें कि ऑपरेटर के सटीक वाक्यविन्यास और अर्थ विश्लेषण पर अभी भी कुछ बहस चल रही है।

अद्यतन (जुलाई 2015): विजुअल स्टूडियो 2015 जारी की गई है और जहाजों एक सी # संकलक कि समर्थन के साथ अशक्त-सशर्त ऑपरेटरों ?.और?[]


10
डॉट के बिना यह सशर्त (ए? बी: सी) ऑपरेटर के साथ कृत्रिम रूप से अस्पष्ट हो जाता है। हम लेक्सिकल निर्माणों से बचने की कोशिश करते हैं जो हमें टोकन स्ट्रीम में मनमाने ढंग से "आगे" देखने की आवश्यकता होती है। (हालांकि, दुर्भाग्य से, सी # में पहले से ही इस तरह के निर्माण हैं; हम इसके बजाय और नहीं जोड़ेंगे।)
एरिक लिपर्ट

33
@ इयान: यह समस्या बेहद आम है। यह सबसे लगातार अनुरोधों में से एक है जो हमें मिलता है।
एरिक लिपर्ट

7
@ इयान: मैं ऐसा करने के लिए संभव होने पर अशक्त ऑब्जेक्ट पैटर्न का उपयोग करना भी पसंद करता हूं, लेकिन ज्यादातर लोगों के पास ऑब्जेक्ट मॉडल के साथ काम करने की लक्जरी नहीं होती है जिसे वे खुद डिज़ाइन करते हैं। मौजूदा ऑब्जेक्ट मॉडल के बहुत सारे नल का उपयोग करते हैं और इसलिए यह है कि दुनिया को हमारे साथ रहना है।
एरिक लिपर्ट

12
@ जॉन: हमें यह सुविधा अनुरोध लगभग पूरी तरह से हमारे सबसे अनुभवी प्रोग्रामर से मिलता है। एमवीपी हर समय इसके लिए पूछते हैं । लेकिन मैं समझता हूं कि राय अलग-अलग होती है; अगर आप अपनी आलोचना के अलावा रचनात्मक भाषा का सुझाव देना चाहते हैं, तो मुझे इस पर विचार करने में खुशी होगी।
एरिक लिपर्ट

28
@lazyberezovsky: मैं कभी भी तथाकथित "कानून" के बारे में नहीं समझ पाया हूँ; सबसे पहले, यह अधिक सटीक रूप से "द सुझाव का सुझाव" कहा जाता है। और दूसरा, "केवल एक सदस्य की पहुंच" को उसके तार्किक निष्कर्ष तक ले जाने का परिणाम है "ईश्वर की वस्तुएं" जहां हर वस्तु को हर ग्राहक के लिए सब कुछ करने की आवश्यकता होती है, न कि उन वस्तुओं को सौंपने में सक्षम होने के बजाय जो ग्राहक को पता है कि कैसे करना है। चाहता हे। मैं लोकतंत्र के कानून के बिल्कुल विपरीत पसंद करता हूं: प्रत्येक वस्तु अच्छी तरह से समस्याओं की एक छोटी संख्या को हल करती है, और उन समाधानों में से एक "यहां एक और वस्तु है जो आपकी समस्या को बेहतर ढंग से हल कर सकती है"
एरिक लिपर्ट

27

मुझे इस सवाल से प्रेरित होकर यह पता लगाने की कोशिश की गई कि अभिव्यक्ति के पेड़ों का उपयोग करके इस प्रकार की गहरी अशांति की जांच कैसे आसान / सुंदर वाक्य रचना के साथ की जा सकती है। हालांकि मैं यह कहते हुए जवाबों से सहमत हूं कि यह एक बुरा डिज़ाइन हो सकता है यदि आपको अक्सर पदानुक्रम में गहरी घटनाओं का उपयोग करने की आवश्यकता होती है, तो मुझे यह भी लगता है कि कुछ मामलों में, जैसे डेटा प्रस्तुति, यह बहुत उपयोगी हो सकता है।

इसलिए मैंने एक एक्सटेंशन विधि बनाई, जो आपको लिखने की अनुमति देगी:

var berries = cake.IfNotNull(c => c.Frosting.Berries);

यदि अभिव्यक्ति का कोई भाग अशक्त नहीं है, तो यह जामुन लौटा देगा। यदि नल का सामना किया जाता है, तो नल वापस आ जाता है। हालांकि, कुछ संस्करण हैं, वर्तमान संस्करण में यह केवल साधारण सदस्य पहुंच के साथ काम करेगा, और यह केवल .NET फ्रेमवर्क 4 पर काम करता है, क्योंकि यह सदस्य एक्सप्रेशन.उपडेट विधि का उपयोग करता है, जो v4 में नया है। यह IfNotNull एक्सटेंशन विधि के लिए कोड है:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace dr.IfNotNullOperator.PoC
{
    public static class ObjectExtensions
    {
        public static TResult IfNotNull<TArg,TResult>(this TArg arg, Expression<Func<TArg,TResult>> expression)
        {
            if (expression == null)
                throw new ArgumentNullException("expression");

            if (ReferenceEquals(arg, null))
                return default(TResult);

            var stack = new Stack<MemberExpression>();
            var expr = expression.Body as MemberExpression;
            while(expr != null)
            {
                stack.Push(expr);
                expr = expr.Expression as MemberExpression;
            } 

            if (stack.Count == 0 || !(stack.Peek().Expression is ParameterExpression))
                throw new ApplicationException(String.Format("The expression '{0}' contains unsupported constructs.",
                                                             expression));

            object a = arg;
            while(stack.Count > 0)
            {
                expr = stack.Pop();
                var p = expr.Expression as ParameterExpression;
                if (p == null)
                {
                    p = Expression.Parameter(a.GetType(), "x");
                    expr = expr.Update(p);
                }
                var lambda = Expression.Lambda(expr, p);
                Delegate t = lambda.Compile();                
                a = t.DynamicInvoke(a);
                if (ReferenceEquals(a, null))
                    return default(TResult);
            }

            return (TResult)a;            
        }
    }
}

यह आपकी अभिव्यक्ति का प्रतिनिधित्व करने वाले अभिव्यक्ति के पेड़ की जांच करके, और एक के बाद एक भागों का मूल्यांकन करके काम करता है; हर बार जाँच करते हैं कि परिणाम शून्य नहीं है।

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


मैं आपके लाम्दा कौशल से प्रभावित हूँ :) वाक्यविन्यास हालांकि एक की तुलना में अधिक जटिल एक बालक सा प्रतीत होता है, अगर कम से कम विवरण परिदृश्य के लिए कम से कम
होमड

कूल, लेकिन यह एक if .. && की तुलना में 100x अधिक कोड की तरह चलता है। यह केवल सार्थक है अगर यह अभी भी नीचे संकलित करता है अगर .. &&।
मॉन्स्टिएर

1
आह और फिर मैंने DynamicInvokeवहाँ देखा । मैं धार्मिक रूप से इससे बचता हूं :)
nawfal

24

मुझे यह एक्सटेंशन गहरे घोंसले के परिदृश्य के लिए काफी उपयोगी लगता है।

public static R Coal<T, R>(this T obj, Func<T, R> f)
    where T : class
{
    return obj != null ? f(obj) : default(R);
}

यह एक ऐसा विचार है जिसे मैंने C # और T-SQL में अशक्त coalescing ऑपरेटर से प्राप्त किया है। अच्छी बात यह है कि रिटर्न प्रकार हमेशा आंतरिक संपत्ति का रिटर्न प्रकार होता है।

इस तरह से आप यह कर सकते हैं:

var berries = cake.Coal(x => x.frosting).Coal(x => x.berries);

... या उपरोक्त की थोड़ी भिन्नता:

var berries = cake.Coal(x => x.frosting, x => x.berries);

यह मुझे पता है सबसे अच्छा वाक्यविन्यास नहीं है, लेकिन यह काम करता है।


क्यों "कोयला", जो एक बेहद डरावना लगता है। ;) हालांकि, अगर फ्रॉस्टिंग अशक्त थे, तो आपका नमूना विफल हो जाएगा। ऐसा दिखना चाहिए: var berries = cake.NullSafe (c => c.Frosting.NullSafe (f => f.Berries));
रॉबर्ट गिसेक

ओह, लेकिन आप अनुमान लगा रहे हैं कि दूसरा तर्क कोल को कॉल नहीं है, जो निश्चित रूप से होना है। यह सिर्फ एक सुविधाजनक परिवर्तन है। चयनकर्ता (x => x.berries) को कोल विधि के अंदर एक कोल कॉल में भेजा जाता है जिसमें दो तर्क होते हैं।
जॉन लेडिग्रेन

को-क्लेशिंग या कोलेस का नाम टी-एसक्यूएल से लिया गया था, यहीं से मुझे पहली बार विचार मिला। IfNotNull का तात्पर्य है कि अगर शून्य नहीं है तो कुछ होता है, हालाँकि जो है, उसे IfNotNull तरीके से नहीं समझाया जाता है। कोयला वास्तव में एक अजीब नाम है, लेकिन यह एक अजीब विधि विलेख में है जिसकी सूचना लेने के लायक है।
जॉन लीडग्रेन

इसके लिए सबसे अच्छा शाब्दिक नाम "ReturnIfNotNull" या "ReturnOrDefault" जैसा कुछ होगा
जॉन लेडिग्रेन

@flq +1 ... हमारी परियोजना में इसे IfNotNull :) भी कहा जाता है
मार्क

16

लॉ ऑफ डेमेटर का उल्लंघन करने के अलावा, जैसा कि मेहरदाद अफशरी ने पहले ही बताया है, मुझे लगता है कि आपको निर्णय तर्क के लिए "गहरी अशांति की जांच" की आवश्यकता है।

यह अक्सर ऐसा होता है जब आप डिफ़ॉल्ट ऑब्जेक्ट्स के साथ खाली ऑब्जेक्ट को बदलना चाहते हैं। इस मामले में आपको नल ऑब्जेक्ट पैटर्न को लागू करने पर विचार करना चाहिए । यह एक वास्तविक वस्तु के लिए स्टैंड-इन के रूप में कार्य करता है, डिफ़ॉल्ट मान और "गैर-कार्रवाई" तरीके प्रदान करता है।


नहीं, उद्देश्य-सी, अशक्त वस्तुओं को संदेश भेजने की अनुमति देता है और यदि आवश्यक हो तो उचित डिफ़ॉल्ट मान लौटाता है। वहां कोई समस्या नहीं।
जोहान्स रूडोल्फ

2
हाँ। यही तो बात है। मूल रूप से, आप अशक्त ऑब्जेक्ट पैटर्न के साथ ObjC व्यवहार का अनुकरण करेंगे।
मेहरदाद अफश्री

10

अपडेट: विज़ुअल स्टूडियो 2015 के साथ शुरू, सी # संकलक (भाषा संस्करण 6) अब ?.ऑपरेटर को पहचानता है , जो एक हवा को "गहरी नल की जाँच" करता है। देखें इस उत्तर जानकारी के लिए।

आपके कोड को फिर से डिज़ाइन करने के अलावा, इस हटाए गए उत्तर की तरह , एक और (यद्यपि भयानक) विकल्प यह try…catchदेखने NullReferenceExceptionके लिए कि गहरी संपत्ति देखने के दौरान कुछ समय बाद होता है, एक ब्लॉक का उपयोग करना होगा ।

try
{
    var x = cake.frosting.berries.loader;
    ...
}
catch (NullReferenceException ex)
{
    // either one of cake, frosting, or berries was null
    ...
}

मैं निम्नलिखित कारणों से व्यक्तिगत रूप से ऐसा नहीं करूंगा:

  • यह अच्छा नहीं लगता है।
  • यह अपवाद से निपटने का उपयोग करता है, जो असाधारण स्थितियों को लक्षित करना चाहिए और ऐसा कुछ नहीं जिसे आप ऑपरेशन के सामान्य पाठ्यक्रम के दौरान अक्सर होने की उम्मीद करते हैं।
  • NullReferenceExceptions को कभी भी स्पष्ट रूप से नहीं पकड़ा जाना चाहिए। ( यह सवाल देखें ।)

तो क्या कुछ विस्तार विधि का उपयोग करना संभव है या यह एक भाषा सुविधा होगी, [...]

यह लगभग निश्चित रूप से एक भाषा सुविधा होगी (जो कि .?और ?[]ऑपरेटरों के रूप में C # 6 में उपलब्ध है ), जब तक कि C # में पहले से अधिक परिष्कृत आलसी मूल्यांकन नहीं था, या जब तक कि आप प्रतिबिंब का उपयोग नहीं करना चाहते हैं (जो संभवतः भी नहीं है प्रदर्शन और प्रकार-सुरक्षा के कारणों के लिए अच्छा विचार)।

चूँकि cake.frosting.berries.loaderकिसी फ़ंक्शन के लिए बस पास होने का कोई तरीका नहीं है (इसका मूल्यांकन किया जाएगा और एक शून्य संदर्भ अपवाद को फेंक दिया जाएगा), आपको निम्नलिखित तरीके से एक सामान्य लुक-अप विधि को लागू करना होगा: यह एक ऑब्जेक्ट और गुणों के नाम में लेता है देखो:

static object LookupProperty( object startingPoint, params string[] lookupChain )
{
    // 1. if 'startingPoint' is null, return null, or throw an exception.
    // 2. recursively look up one property/field after the other from 'lookupChain',
    //    using reflection.
    // 3. if one lookup is not possible, return null, or throw an exception.
    // 3. return the last property/field's value.
}

...

var x = LookupProperty( cake, "frosting", "berries", "loader" );

(नोट: कोड संपादित किया गया।)

आप जल्दी से इस तरह के दृष्टिकोण के साथ कई समस्याएं देखते हैं। सबसे पहले, आपको किसी भी प्रकार की सुरक्षा नहीं मिलती है और एक साधारण प्रकार के संपत्ति मूल्यों की संभावित मुक्केबाजी होती है। दूसरा, आप या nullतो कुछ गलत होने पर वापस लौट सकते हैं, और आपको अपने कॉलिंग फ़ंक्शन में इसके लिए जांचना होगा, या आप एक अपवाद फेंक देंगे, और आप वहीं हैं जहां आपने शुरू किया था। तीसरा, यह धीमा हो सकता है। चौथा, जो आपने शुरू किया था, उससे कहीं ज्यादा यह बदसूरत दिखता है।

[...], या यह सिर्फ एक बुरा विचार है?

मैं या तो साथ रहूँगा:

if (cake != null && cake.frosting != null && ...) ...

या मेहरदाद अफशरी के उपरोक्त उत्तर के साथ जाएं।


पुनश्च: जब मैंने यह उत्तर लिखा था, तो मैंने स्पष्ट रूप से लैम्ब्डा कार्यों के लिए अभिव्यक्ति के पेड़ पर विचार नहीं किया था; इस दिशा में समाधान के लिए उदा @driis का उत्तर देखें। यह एक प्रकार के प्रतिबिंब पर भी आधारित है और इस प्रकार यह बहुत अच्छा प्रदर्शन नहीं कर सकता है और साथ ही एक सरल समाधान ( if (… != null & … != null) …) भी हो सकता है, लेकिन इसे सिंटैक्स पॉइंट-ऑफ-व्यू से अच्छा माना जा सकता है।


2
मुझे नहीं पता कि यह क्यों अस्वीकृत किया गया था, मैंने संतुलन के लिए एक अपवोट किया: उत्तर सही है और एक नए पहलू में लाता है (और इस समाधान की कमियों का स्पष्ट रूप से उल्लेख करता है ...)
मार्टिनस्टेनर

"मेहरदाद अफशरी द्वारा उपरोक्त उत्तर" कहां है?
मार्सन माओ

1
@MarsonMao: उस उत्तर को इस बीच हटा दिया गया है। (आप अभी भी इसे पढ़ सकते हैं यदि आपकी एसओ रैंक पर्याप्त रूप से अधिक है।) मेरी गलती को इंगित करने के लिए धन्यवाद: मुझे हाइपरलिंक का उपयोग करते हुए अन्य उत्तरों का उल्लेख करना चाहिए, "ऊपर देखें" / "नीचे देखें" जैसे शब्दों का उपयोग न करें (जब से उत्तर एक निश्चित क्रम में प्रकट नहीं होते हैं)। मैंने अपना उत्तर अपडेट कर दिया है।
stakx - अब

5

जबकि ड्रीसिस का जवाब दिलचस्प है, मुझे लगता है कि यह थोड़ा महंगा प्रदर्शन बुद्धिमान है। कई प्रतिनिधियों को संकलित करने के बजाय, मैं एक लैम्ब्डा को प्रति संपत्ति पथ पर संकलित करना चाहता हूं, इसे कैश करना और फिर इसे कई प्रकारों को फिर से स्थापित करना।

नीचे NullCoalesce बस इतना ही करता है, यह अशक्त जाँच के साथ एक नया लैंबडा एक्सप्रेशन और डिफ़ॉल्ट (TResult) की वापसी देता है यदि कोई रास्ता अशक्त है।

उदाहरण:

NullCoalesce((Process p) => p.StartInfo.FileName)

एक अभिव्यक्ति लौटाएगा

(Process p) => (p != null && p.StartInfo != null ? p.StartInfo.FileName : default(string));

कोड:

    static void Main(string[] args)
    {
        var converted = NullCoalesce((MethodInfo p) => p.DeclaringType.Assembly.Evidence.Locked);
        var converted2 = NullCoalesce((string[] s) => s.Length);
    }

    private static Expression<Func<TSource, TResult>> NullCoalesce<TSource, TResult>(Expression<Func<TSource, TResult>> lambdaExpression)
    {
        var test = GetTest(lambdaExpression.Body);
        if (test != null)
        {
            return Expression.Lambda<Func<TSource, TResult>>(
                Expression.Condition(
                    test,
                    lambdaExpression.Body,
                    Expression.Default(
                        typeof(TResult)
                    )
                ),
                lambdaExpression.Parameters
            );
        }
        return lambdaExpression;
    }

    private static Expression GetTest(Expression expression)
    {
        Expression container;
        switch (expression.NodeType)
        {
            case ExpressionType.ArrayLength:
                container = ((UnaryExpression)expression).Operand;
                break;
            case ExpressionType.MemberAccess:
                if ((container = ((MemberExpression)expression).Expression) == null)
                {
                    return null;
                }
                break;
            default:
                return null;
        }
        var baseTest = GetTest(container);
        if (!container.Type.IsValueType)
        {
            var containerNotNull = Expression.NotEqual(
                container,
                Expression.Default(
                    container.Type
                )
            );
            return (baseTest == null ?
                containerNotNull :
                Expression.AndAlso(
                    baseTest,
                    containerNotNull
                )
            );
        }
        return baseTest;
    }

4

एक विकल्प नल ऑब्जेक्ट पैटन का उपयोग करना है, इसलिए जब आपके पास केक नहीं है, तो अशक्त होने के बजाय, आपके पास एक नलकूप है जो एक नलफॉस्टिंग लौटाता है। क्षमा करें मैं यह समझाने में बहुत अच्छा नहीं हूं, लेकिन अन्य लोग हैं, देखें


3

मैं भी अक्सर एक सरल वाक्यविन्यास के लिए कामना की है! यह विशेष रूप से बदसूरत हो जाता है जब आपके पास विधि-रिटर्न-मान होते हैं जो शून्य हो सकते हैं, क्योंकि तब आपको अतिरिक्त चर की आवश्यकता होती है (उदाहरण के लिए cake.frosting.flavors.FirstOrDefault().loader) :

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

var loader = NullSafe.Chain(cake, c=>c.frosting, f=>f.berries, b=>b.loader);

यहाँ कार्यान्वयन है:

public static TResult Chain<TA,TB,TC,TResult>(TA a, Func<TA,TB> b, Func<TB,TC> c, Func<TC,TResult> r) 
where TA:class where TB:class where TC:class {
    if (a == null) return default(TResult);
    var B = b(a);
    if (B == null) return default(TResult);
    var C = c(B);
    if (C == null) return default(TResult);
    return r(C);
}

मैंने कई ओवरलोड (2 से 6 मापदंडों के साथ), साथ ही ओवरलोड भी बनाए जो श्रृंखला को एक मूल्य-प्रकार या डिफ़ॉल्ट के साथ समाप्त करने की अनुमति देते हैं। यह मेरे लिए वास्तव में अच्छी तरह से काम करता है!


1

नहीं है हो सकता है कि codeplex परियोजना को लागू करने वाली हो सकता है कि या IfNotNull सी # में गहरी भाव के लिए lambdas का उपयोग कर

उपयोग का उदाहरण:

int? CityId= employee.Maybe(e=>e.Person.Address.City);

इसी तरह के प्रश्न में लिंक का सुझाव दिया गया था कि एक गहरी लंबोदर अभिव्यक्ति में नल की जांच कैसे करें?


1

जैसा कि जॉन लेदरग्रेन में सुझाया गया है के उत्तर , काम के आसपास एक दृष्टिकोण विस्तार विधियों और प्रतिनिधियों का उपयोग करना है। इनके प्रयोग से कुछ इस तरह दिख सकता है:

int? numberOfBerries = cake
    .NullOr(c => c.Frosting)
    .NullOr(f => f.Berries)
    .NullOr(b => b.Count());

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


1

या आप प्रतिबिंब का उपयोग कर सकते हैं :)

परावर्तन समारोह:

public Object GetPropValue(String name, Object obj)
    {
        foreach (String part in name.Split('.'))
        {
            if (obj == null) { return null; }

            Type type = obj.GetType();
            PropertyInfo info = type.GetProperty(part);
            if (info == null) { return null; }

            obj = info.GetValue(obj, null);
        }
        return obj;
    }

उपयोग:

object test1 = GetPropValue("PropertyA.PropertyB.PropertyC",obj);

मेरा मामला (परावर्तन समारोह में अशक्त के बजाय DBNull.Value लौटाएँ):

cmd.Parameters.AddWithValue("CustomerContactEmail", GetPropValue("AccountingCustomerParty.Party.Contact.ElectronicMail.Value", eInvoiceType));

1

इस कोड को आज़माएं:

    /// <summary>
    /// check deep property
    /// </summary>
    /// <param name="obj">instance</param>
    /// <param name="property">deep property not include instance name example "A.B.C.D.E"</param>
    /// <returns>if null return true else return false</returns>
    public static bool IsNull(this object obj, string property)
    {
        if (string.IsNullOrEmpty(property) || string.IsNullOrEmpty(property.Trim())) throw new Exception("Parameter : property is empty");
        if (obj != null)
        {
            string[] deep = property.Split('.');
            object instance = obj;
            Type objType = instance.GetType();
            PropertyInfo propertyInfo;
            foreach (string p in deep)
            {
                propertyInfo = objType.GetProperty(p);
                if (propertyInfo == null) throw new Exception("No property : " + p);
                instance = propertyInfo.GetValue(instance, null);
                if (instance != null)
                    objType = instance.GetType();
                else
                    return true;
            }
            return false;
        }
        else
            return true;
    }

0

मैंने कल रात यह पोस्ट किया और फिर एक मित्र ने मुझे इस प्रश्न की ओर इशारा किया। आशा करता हूँ की ये काम करेगा। फिर आप कुछ इस तरह से कर सकते हैं:

var color = Dis.OrDat<string>(() => cake.frosting.berries.color, "blue");


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace DeepNullCoalescence
{
  public static class Dis
  {
    public static T OrDat<T>(Expression<Func><T>> expr, T dat)
    {
      try
      {
        var func = expr.Compile();
        var result = func.Invoke();
        return result ?? dat; //now we can coalesce
      }
      catch (NullReferenceException)
      {
        return dat;
      }
    }
  }
}

पूरी ब्लॉग पोस्ट यहाँ पढ़ें ।

उसी मित्र ने यह भी सुझाव दिया कि आप इसे देखें


3
Expressionयदि आप बस संकलन और पकड़ने जा रहे हैं तो परेशान क्यों हों? बस एक का उपयोग करें Func<T>
स्कॉट रिपी

0

मैंने पूछे गए प्रश्न के लिए काम करने के लिए यहाँ से कोड को थोड़ा संशोधित किया :

public static class GetValueOrDefaultExtension
{
    public static TResult GetValueOrDefault<TSource, TResult>(this TSource source, Func<TSource, TResult> selector)
    {
        try { return selector(source); }
        catch { return default(TResult); }
    }
}

और हाँ, यह प्रदर्शन के निहितार्थ को पकड़ने / पकड़ने के लिए संभवत: इष्टतम समाधान नहीं है, लेकिन यह काम करता है:>

उपयोग:

var val = cake.GetValueOrDefault(x => x.frosting.berries.loader);

0

जहाँ आपको इसे हासिल करने की आवश्यकता है, यह करें:

प्रयोग

Color color = someOrder.ComplexGet(x => x.Customer.LastOrder.Product.Color);

या

Color color = Complex.Get(() => someOrder.Customer.LastOrder.Product.Color);

हेल्पर वर्ग का क्रियान्वयन

public static class Complex
{
    public static T1 ComplexGet<T1, T2>(this T2 root, Func<T2, T1> func)
    {
        return Get(() => func(root));
    }

    public static T Get<T>(Func<T> func)
    {
        try
        {
            return func();
        }
        catch (Exception)
        {
            return default(T);
        }
    }
}

-3

मुझे ऑब्जेक्टिव-सी द्वारा लिया गया दृष्टिकोण पसंद है:

"वस्तुनिष्ठ-सी भाषा इस समस्या के लिए एक और दृष्टिकोण लेती है और नील पर तरीकों का आह्वान नहीं करती है, बल्कि ऐसे सभी आह्वान के लिए शून्य लौटाती है।"

if (cake.frosting.berries != null) 
{
    var str = cake.frosting.berries...;
}

1
कोई अन्य भाषा क्या करती है (और आपकी राय) इसे सी # में काम करने के लिए लगभग पूरी तरह अप्रासंगिक है। यह किसी को भी उनके C # समस्या को हल करने में मदद नहीं करता है
एडीसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.