গভীর নাল চেকিং, আরও ভাল উপায় আছে?


130

দ্রষ্টব্য: সি # 6 / ভিজ্যুয়াল স্টুডিও 2015- .?অপারেটর প্রবর্তনের আগে এই প্রশ্ন জিজ্ঞাসা করা হয়েছিল ।

আমরা সবাই সেখানে ছিলাম, আমাদের কাছে কেক.ফ্রস্টিং.বেরিজ.ল্ডারের মতো কিছু গভীর সম্পত্তি রয়েছে যা আমাদের নালাগুলি যাচাই করা উচিত তাই এর কোনও ব্যতিক্রম নেই। করার উপায় হ'ল বিবৃতি যদি একটি শর্ট সার্কিট ব্যবহার করা হয়

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

এটি ঠিক মার্জিত নয়, এবং পুরো চেইনটি পরীক্ষা করার জন্য সম্ভবত এটির সহজ উপায় হওয়া উচিত এবং এটি নাল ভেরিয়েবল / সম্পত্তির বিরুদ্ধে আসে কিনা তা দেখতে পাওয়া উচিত।

এটি কি কোনও এক্সটেনশন পদ্ধতি ব্যবহার করে সম্ভব বা এটি কোনও ভাষা বৈশিষ্ট্য হবে, বা এটি কেবল একটি খারাপ ধারণা?


3
আমি প্রায়শই এটির জন্য যথেষ্ট ইচ্ছা করেছিলাম - তবে আমি যে সমস্ত ধারণা নিয়ে এসেছি তা প্রকৃত সমস্যার চেয়ে খারাপ ছিল than
পিটারচেন

সমস্ত উত্তরের জন্য ধন্যবাদ এবং এটি দেখতে আকর্ষণীয় যে অন্যান্য ব্যক্তিদেরও একই চিন্তাভাবনা ছিল। আমি কীভাবে এই সমস্যাটি সমাধান করেছি তা দেখতে আমি কীভাবে ভাবতে চাই এবং যদিও এরিকের সমাধানগুলি বেশ ভাল আমি মনে করি আমি কেবল (ইসনুল (এবিসি)), বা (ইসনটনল (এবিসি)) এর মতো কিছু লিখতে চাই তবে সম্ভবত এটি কেবল আমার
স্বাদেই

আপনি যখন ফ্রস্টিং তাত্ক্ষণিকভাবে চালু করেন, তখন এটির বেরিগুলির একটি সম্পত্তি থাকে, তাই আপনার নির্মাতার সেই মুহুর্তে, আপনি কেবল ফ্রস্টিংকে বলতে পারেন যে যখনই এটি খালি (নাল নয়) বেরি তৈরি করার জন্য তত্পর হয়? এবং যখনই বেরিগুলি ফ্রস্টিং পরিবর্তন করা হয় তখন মানটি পরীক্ষা করে ????
ডগ চেম্বারলাইন

কিছুটা looseিলে .ালাভাবে সম্পর্কিত, কয়েকটি কৌশল এখানে ঘুরে দেখার চেষ্টা করছিলাম এমন "গভীর নাল" সমস্যার জন্য আমি পছন্দনীয় পেলাম। stackoverflow.com/questions/818642/...
AaronLS

উত্তর:


223

আমরা একটি নতুন অপারেশন "?" যুক্ত করার কথা বিবেচনা করেছি। আপনি চান শব্দার্থবিদ্যা আছে ভাষা। (এবং এটি এখন যোগ করা হয়েছে; নীচে দেখুন)) এটি, আপনি বলতে চাইবেন

cake?.frosting?.berries?.loader

এবং সংকলকটি আপনার জন্য সমস্ত সংক্ষিপ্ত-প্রচারকারী চেক তৈরি করবে।

এটি সি # 4 এর জন্য বারটি তৈরি করেনি সম্ভবত ভাষার কোনও কাল্পনিক ভবিষ্যতের সংস্করণের জন্য।

আপডেট (2014):?. অপারেটর এখন পরিকল্পিত পরবর্তী Roslyn কম্পাইলার মুক্তির জন্য। দ্রষ্টব্য যে অপারেটরের সঠিক সিনট্যাকটিক এবং শব্দার্থ বিশ্লেষণ নিয়ে এখনও কিছু বিতর্ক রয়েছে।

আপডেট (জুলাই 2015): ভিজ্যুয়াল স্টুডিও 2015 প্রকাশিত হয়েছে এবং একটি সি # সংকলক সহ জাহাজগুলি শূন্য শর্তাধীন অপারেটর ?.এবং?[] সমর্থন করে ।


10
বিন্দু ছাড়াই এটি শর্তাধীন (এ? বি: সি) অপারেটরের সাথে সিনট্যাক্টিকালি দ্বিধাহীন হয়ে পড়ে। আমরা লেকিকাল নির্মাণগুলি এড়ানোর চেষ্টা করি যা টোকেন স্ট্রিমের মধ্যে আমাদের নির্বিচারে "এগিয়ে" দেখা দরকার। (যদিও, দুর্ভাগ্যক্রমে, সি # তে ইতিমধ্যে এমন নির্মাণ রয়েছে; আমরা বরং আরও কিছু যোগ করতে চাই না))
এরিক লিপার্ট

33
@ আইয়ান: এই সমস্যাটি অত্যন্ত সাধারণ। এটি আমাদের কাছে পাওয়া প্রায়শই অনুরোধ।
এরিক লিপার্ট

7
@ আইয়ান: আমি যখন এটি সম্ভব হবে তখন নাল বস্তুর প্যাটার্নটিও ব্যবহার করতে পছন্দ করি তবে বেশিরভাগ লোকেরা নিজেরাই ডিজাইন করেছেন এমন বস্তুর মডেলগুলির সাথে কাজ করার বিলাসিতা নেই। প্রচুর বিদ্যমান অবজেক্ট মডেল নাল ব্যবহার করে এবং তাই আমাদের সাথেই বাঁচতে হবে world
এরিক লিপার্ট

12
@ জন: আমরা আমাদের অভিজ্ঞ অভিজ্ঞ প্রোগ্রামারদের কাছ থেকে প্রায় পুরোপুরি এই বৈশিষ্ট্যটির অনুরোধটি পাই । এমভিপিরা সর্বদা এটি চেয়ে থাকে । তবে আমি বুঝতে পারি যে মতামত পৃথক; আপনি যদি আপনার সমালোচনার পাশাপাশি গঠনমূলক ভাষার নকশার পরামর্শ দিতে চান তবে আমি এটি বিবেচনা করে খুশি।
এরিক লিপার্ট

28
@ লাজিবেরেজভস্কি: আমি কখনই ডেমিটারের তথাকথিত "আইন" বুঝতে পারি নি; প্রথমত, এটি আরও সঠিকভাবে "ডিমিটারের পরামর্শ" বলে অভিহিত হয়। এবং দ্বিতীয়ত, "কেবলমাত্র একজন সদস্যের অ্যাক্সেস" এর যৌক্তিক উপসংহারে নেওয়ার ফলাফলটি হ'ল "Godশ্বরের অবজেক্টস" যেখানে ক্লায়েন্ট কীভাবে কীভাবে করতে হয় তা জানে এমন বস্তুগুলি হস্তান্তর করতে সক্ষম হওয়ার পরিবর্তে প্রতিটি ক্লায়েন্টের জন্য সমস্ত কিছু করার প্রয়োজন হয় than চায়। আমি ডেমিটারের আইনের ঠিক বিপরীতটি পছন্দ করি: প্রতিটি বস্তু একটি সংখ্যক সমস্যা ভালভাবে সমাধান করে এবং এর সমাধানগুলির মধ্যে একটি হতে পারে "এখানে অন্য একটি বিষয় যা আপনার সমস্যাটিকে আরও ভালভাবে সমাধান করে"
এরিক লিপার্ট

27

আমি এই প্রশ্নের দ্বারা অনুপ্রাণিত হয়ে চেষ্টা করেছি এবং এক্সপ্রেশন ট্রি ব্যবহার করে কীভাবে একটি সহজ / প্রিটিয়ের সিনট্যাক্স দিয়ে এই জাতীয় গভীর নাল চেক করা যায় তা জানতে। যদিও আমি উত্তরগুলির সাথে একমত হয়েছি যে এটি একটি খারাপ নকশা হতে পারে যদি আপনাকে প্রায়শই স্তরক্রমের গভীরে উদাহরণগুলি অ্যাক্সেস করতে হয় তবে আমি মনে করি যে কিছু ক্ষেত্রে যেমন ডেটা উপস্থাপনা, এটি খুব দরকারী হতে পারে।

সুতরাং আমি একটি এক্সটেনশন পদ্ধতি তৈরি করেছি, এটি আপনাকে লেখার অনুমতি দেবে:

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

অভিব্যক্তির কোনও অংশ শূন্য না হলে এটি বেরিগুলি ফিরিয়ে দেবে। যদি নাল সম্মুখীন হয়, নাল ফিরে আসে। কিছু সতর্কতা রয়েছে যদিও বর্তমান সংস্করণে এটি কেবলমাত্র সাধারণ সদস্য অ্যাক্সেস নিয়ে কাজ করবে এবং এটি কেবল নেট নেট ফ্রেমওয়ার্ক 4 এ কাজ করে, কারণ এটি সদস্যপ্রেম.অ্যাপডেট পদ্ধতি ব্যবহার করে, যা ভি 4-তে নতুন। এটি 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;            
        }
    }
}

এটি আপনার ভাবের প্রতিনিধিত্বকারী এক্সপ্রেশন ট্রি পরীক্ষা করে এবং একের পর এক অংশগুলি মূল্যায়ন করে কাজ করে; ফলাফলটি শূন্য নয় এমন প্রতিবার পরীক্ষা করা।

আমি নিশ্চিত যে এটি বাড়ানো যেতে পারে যাতে সদস্য এক্সপ্রেসনের চেয়ে অন্যান্য অভিব্যক্তি সমর্থনযোগ্য। এটিকে প্রুফ-অফ-কনসেপ্ট কোড হিসাবে বিবেচনা করুন এবং দয়া করে মনে রাখবেন এটি ব্যবহার করে পারফরম্যান্স পেনাল্টি হবে (যা সম্ভবত বেশিরভাগ ক্ষেত্রে কার্যকর হবে না, তবে এটি একটি দৃ tight় লুপে ব্যবহার করবেন না :-))


আমি আপনার ল্যাম্বদা দক্ষতায় মুগ্ধ হয়েছি :) সিনট্যাক্সটি তবে তার চেয়ে বেশি জটিল বলে মনে হচ্ছে, যদি বিবৃতি দৃশ্যের জন্য কমপক্ষে হয়
হামদে

দুর্দান্ত তবে এটি যদি ইএন্ড .. ও এন্ডের চেয়ে 100x বেশি কোডের মতো চলে। এটি তখনও সার্থক যখন এটি যদি এখনও একটি if .. && এর কাছে সংকলিত হয়।
মনস্টিয়র

1
আহ এবং তারপর আমি DynamicInvokeসেখানে দেখেছি । আমি ধর্মীয়ভাবে এড়িয়ে
চলেছি

24

গভীর বাসা বাঁধার দৃশ্যের জন্য আমি এই এক্সটেনশনটি বেশ কার্যকর বলে খুঁজে পেয়েছি।

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

এটি একটি ধারণা যা আমি সি # এবং টি এসকিউএল এর নাল কোলেসিং অপারেটর থেকে পেয়েছি। সুন্দর জিনিস হ'ল রিটার্নের ধরণটি সর্বদা অভ্যন্তরীণ সম্পত্তির রিটার্নের ধরণ।

এইভাবে আপনি এটি করতে পারেন:

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

... বা উপরের কিছুটা ভিন্নতা:

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

এটি আমার জানা সেরা সিনট্যাক্স নয়, তবে এটি কাজ করে।


কেন "কয়লা", এটি অত্যন্ত চতুর দেখাচ্ছে। ;) তবে, আপনার নমুনা ব্যর্থ হবে যদি ফ্রস্টিং শূন্য হয়। এর মতো দেখতে হবে: var বেরি = কেক। নলস্যাফ (সি => সি। ফ্রস্টিং।নুলস্যাফ (এফ => এফ। বেরি));
রবার্ট জিসেকেক

ওহ, তবে আপনি বোঝাচ্ছেন যে দ্বিতীয় যুক্তি হ'ল কয়লার কল নয় যা এটি অবশ্যই হওয়া উচিত। এটি কেবল একটি সুবিধাজনক পরিবর্তন। নির্বাচক (x => x.berries) দুটি কয়লা পদ্ধতিতে কয়লা পদ্ধতির অভ্যন্তরে একটি কল কল পাঠানো হয়।
জন লিডেগ্রেন

কোয়েলেসিং বা কোলেসেস নামটি টি-এসকিউএল থেকে নেওয়া হয়েছিল, এটিই আমি প্রথম ধারণা পেয়েছিলাম। IfNotNull ইঙ্গিত দেয় যে নাল না থাকলে কিছু ঘটেছিল, তবে এটি যা হয়, তা ifNotNull পদ্ধতি কল দ্বারা ব্যাখ্যা করা হয়নি। কয়লা প্রকৃতপক্ষে একটি বিজোড় নাম, তবে এটি নোটিশে নেওয়ার মতো একটি অদ্ভুত পদ্ধতি de
জন লিডেগ্রেন

এর সর্বোত্তম আক্ষরিক নাম "রিটার্নআইফনট নল" বা "রিটার্নঅরডিফল্ট" এর মতো কিছু হবে
জন লেইডগ্রেন

@ ফ্ল্যাক +১ ... আমাদের প্রকল্পে এটিও IfNotNull নামক :)
মার্ক Sigrist

16

ডিমেটার আইন লঙ্ঘন করার পাশাপাশি, যেমন মেহরদাদ আফশারি ইতিমধ্যে উল্লেখ করেছেন, মনে হয় সিদ্ধান্তের যুক্তির জন্য আপনার "গভীর নাল চেকিং" দরকার need

আপনি যখন ডিফল্ট মান সহ খালি বস্তুগুলি প্রতিস্থাপন করতে চান তখন এটি প্রায়শই ঘটে। এই ক্ষেত্রে আপনার নাল অবজেক্ট প্যাটার্নটি প্রয়োগ করা বিবেচনা করা উচিত । এটি একটি বাস্তব অবজেক্টের জন্য স্ট্যান্ড-ইন হিসাবে কাজ করে, ডিফল্ট মান এবং "অ-অ্যাকশন" পদ্ধতি সরবরাহ করে।


না, উদ্দেশ্য-সি নাল বস্তুগুলিতে বার্তা প্রেরণের অনুমতি দেয় এবং প্রয়োজনে যথাযথ ডিফল্ট মান প্রদান করে। সমস্যা নেই।
জোহানেস রুডলফ

2
হ্যাঁ। এটাই আসল কথা. মূলত, আপনি নাল অবজেক্ট প্যাটার্ন দিয়ে ওবিজেসি আচরণ অনুকরণ করবেন।
মেহরদাদ আফশারি

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
    ...
}

নিম্নলিখিত কারণে আমি ব্যক্তিগতভাবে এটি করব না:

  • দেখতে সুন্দর লাগছে না।
  • এটি ব্যতিক্রম হ্যান্ডলিং ব্যবহার করে, যা ব্যতিক্রমী পরিস্থিতি লক্ষ্য করে এবং এমন কোনও কিছু নয় যা আপনি সাধারণত অপারেশন চলাকালীন সময়ে ঘটবে বলে আশা করেন।
  • NullReferenceExceptionগুলি সম্ভবত স্পষ্টভাবে ধরা উচিত নয়। ( এই প্রশ্নটি দেখুন ।)

তাহলে কি কিছু এক্সটেনশন পদ্ধতি ব্যবহার করা সম্ভব বা এটি কোনও ভাষা বৈশিষ্ট্য হবে, [...]

এই প্রায় অবশ্যই একটি ভাষা বৈশিষ্ট্য (যা আকারে সি # 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 && ...) ...

বা মেহরদাদ আফশারী উপরের উত্তরটি দিয়ে যান।


পিএস: ফিরে যখন আমি এই উত্তরটি লিখেছিলাম, আমি স্পষ্টতই ল্যাম্বডা ফাংশনের জন্য অভিব্যক্তি গাছগুলি বিবেচনা করি নি; এই দিক থেকে সমাধানের জন্য যেমন @ ডিরিয়াসের উত্তর দেখুন। এটি একধরণের প্রতিবিম্বের উপরও নির্ভরশীল এবং এটি একটি সহজ সমাধান ( if (… != null & … != null) …) এর পাশাপাশি কার্যকরভাবে সম্পাদন করতে পারে না তবে এটি সিনট্যাক্স পয়েন্ট অফ ভিউ থেকে আরও ভাল বিচার করা যেতে পারে।


2
আমি জানি না কেন এটিকে হ্রাস করা হয়েছিল, আমি ভারসাম্যের জন্য উত্সাহ দিয়েছিলাম: উত্তর সঠিক এবং একটি নতুন দিক নিয়ে এসেছে (এবং স্পষ্টতই এই সমাধানের অসুবিধাগুলির উল্লেখ আছে ...)
অসুবিধাগুলির

"মেহেরদাদ আফশারীর উপরের উত্তর" কোথায়?
মারসন মাও

1
@ মার্সনমাও: এর মধ্যেই উত্তরটি মুছে ফেলা হয়েছে। (যদি আপনার এসও র‌্যাঙ্ক পর্যাপ্ত পরিমাণে থাকে তবে আপনি এটি পড়তে সক্ষম হন)) আমার ভুলটি উল্লেখ করার জন্য ধন্যবাদ: "হাইপারলিংক" ব্যবহার করে অন্যান্য উত্তরগুলি উল্লেখ করা উচিত, "উপরে দেখুন" / "নীচে দেখুন" জাতীয় শব্দ ব্যবহার না করে (যেহেতু উত্তরগুলি একটি নির্দিষ্ট ক্রমে হাজির হয় না)। আমি আমার উত্তর আপডেট করেছি।
স্টাকেক্স -

5

যদিও ড্রিসের উত্তর আকর্ষণীয়, তবে আমি মনে করি এটি সামান্য ব্যয়বহুল পারফরম্যান্সের ভিত্তিতে। অনেক প্রতিনিধি সংকলন করার পরিবর্তে, আমি সম্পত্তি গতিপথের জন্য একটি ল্যাম্বদা সংকলন, এটি ক্যাশে এবং তারপরে বহু ধরণের পুনরায় বিবাদ পছন্দ করতে চাই।

নীচের নালকোলেসেস কেবল এটি করে, এটি নাল চেক সহ একটি নতুন ল্যাম্বডা এক্সপ্রেশন এবং কোনও পথ শূন্য হলে ক্ষেত্রে ডিফল্ট (ট্রিসল্ট) ফেরত দেয়।

উদাহরণ:

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

একটি বিকল্প হ'ল নাল অবজেক্ট প্যাটেন ব্যবহার করা, সুতরাং আপনার যখন কেক নেই তখন নাল থাকার পরিবর্তে আপনার কাছে নলকেক রয়েছে যা একটি নালফস্টিং ফিরিয়ে দেয় Sorry দুঃখিত, আমি এটি ব্যাখ্যা করতে খুব ভাল নই তবে অন্যান্য লোকেরাও দেখুন, দেখুন


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 C # গভীর এক্সপ্রেশন জন্য lambdas ব্যবহার

ব্যবহারের উদাহরণ:

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

লিঙ্কটি অনুরূপ প্রশ্নে পরামর্শ দেওয়া হয়েছিল কীভাবে গভীর ল্যাম্বডা অভিব্যক্তিতে নালগুলির জন্য চেক করবেন?


1

হিসাবে প্রস্তাব জন Leidegren এর উত্তর , এর এক পদ্ধতির কাজ প্রায় এই এক্সটেনশনটি পদ্ধতি ও প্রতিনিধিদের ব্যবহার করা হয়। এগুলি ব্যবহার করে এমন কিছু দেখতে পাওয়া যায়:

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);

আমার কেস (প্রতিবিম্ব ফাংশনে নাল পরিবর্তে ডিবি নল.ভ্যালু ফিরিয়ে দিন):

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
অন্য কোন ভাষা কী করে (এবং এটি সম্পর্কে আপনার মতামত) এটি সি # তে কাজ করার জন্য প্রায় সম্পূর্ণ অপ্রাসঙ্গিক। এটি কাউকে তাদের সি # সমস্যা সমাধান করতে সহায়তা করে না
এডিসন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.