সংগ্রহ শূন্য হলে নেট নেট ফোরচ লুপ নুলআরফএক্সসেপশনটি কেন ফেলে?


231

সুতরাং আমি প্রায়শই এই পরিস্থিতিতে চলে যাই ... যেখানে Do.Something(...)নাল সংগ্রহটি দেয়, যেমন:

int[] returnArray = Do.Something(...);

তারপরে, আমি এই সংগ্রহটি এর মতো ব্যবহার করার চেষ্টা করি:

foreach (int i in returnArray)
{
    // do some more stuff
}

আমি কেবল কৌতূহলী, কেন নালাগুলি সংগ্রহের জন্য ফোরচ লুপ কাজ করতে পারে না? এটা আমার কাছে যৌক্তিক মনে হয় যে 0 টি পুনরাবৃত্তি নাল সংগ্রহের সাথে সম্পাদিত হবে ... পরিবর্তে এটি একটি নিক্ষেপ করবে NullReferenceException। কেউ হতে পারে কেন এমন হতে পারে?

আমি বিরক্তিকর হয়ে উঠছি কারণ আমি এমন APIs নিয়ে কাজ করছি যা তারা ঠিক কী ফিরে আসে সে সম্পর্কে পরিষ্কার নয়, তাই আমি if (someCollection != null)সর্বত্রই শেষ করি ...

সম্পাদনা করুন: যেগুলি foreachব্যবহার করে তা ব্যাখ্যা করার জন্য আপনাকে সকলকে ধন্যবাদ GetEnumeratorএবং যদি কোনও গণক না পাওয়া থাকে তবে ভবিষ্যদ্বাণীটি ব্যর্থ হবে। আমি অনুমান করি যে আমি কেন ভাষা / রানটাইম এনুমरेटरটি ধরার আগে নাল চেক করতে পারব না বা করবে না। আমার কাছে মনে হয় যে আচরণটি এখনও ভালভাবে সংজ্ঞায়িত হবে।


1
অ্যারেটিকে সংগ্রহ হিসাবে কল্পনা করার জন্য কিছু ভুল feels তবে সম্ভবত আমি কেবল পুরানো স্কুল।
রোব্যাটিকাস

হ্যাঁ, আমি একমত ... আমি এখনও নিশ্চিত নই কেন এই কোড বেসে এতগুলি পদ্ধতি অ্যারে x_x প্রদান করে
পোলারিস 878

4
আমি মনে করি একই যুক্তিতে এটি সি # তে সমস্ত বিবৃতিতে কোনও nullমান দেওয়া হলে অপ-অপশনে পরিণত হওয়ার জন্য সংজ্ঞায়িত হবে । আপনি কি কেবল foreachলুপ বা অন্যান্য বিবৃতিতেও এটি পরামর্শ দিচ্ছেন ?
কেন

7
@ কেন ... আমি কেবল ভবিষ্যতের লুপগুলি ভাবছি, কারণ আমার কাছে প্রোগ্রামারের কাছে এটি স্পষ্ট বলে মনে হয় যে সংগ্রহটি খালি বা অস্তিত্বহীন থাকলে কিছুই ঘটবে না
পোলারিস 878

উত্তর:


251

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

আপনার যদি সত্যিই এমন কিছু করার দরকার হয় তবে নাল কোলেসিং অপারেটরটি ব্যবহার করে দেখুন:

int[] array = null;

foreach (int i in array ?? Enumerable.Empty<int>())
{
   System.Console.WriteLine(string.Format("{0}", i));
}

3
আমার অজ্ঞতা দয়া করে ক্ষমা করুন, কিন্তু এই দক্ষ? এটি কি প্রতিটি পুনরাবৃত্তির সাথে তুলনা করে না?
ব্যবহারকারী 919426

20
আমি বিশ্বাস করি না। উত্পন্ন আইএলটির দিকে তাকানো, লুপটি নাল তুলনা করার পরে।
রোব্যাটিকাস

10
হোলি নেক্রো ... কখনও কখনও আপনাকে কোনও দক্ষতা হিট হয় কিনা তা নির্ধারণের জন্য সংকলকটি কী করছে তা দেখতে আপনাকে আইএলটির দিকে নজর দিতে হবে। ব্যবহারকারী 919426 জিজ্ঞাসা করেছিল যে এটি প্রতিটি পুনরাবৃত্তির জন্য পরীক্ষা করে কিনা। যদিও উত্তরটি কিছু লোকের কাছে সুস্পষ্ট হতে পারে তবে এটি সবার কাছে সুস্পষ্ট নয় এবং আইএলটি দেখলে সংকলকটি কী করছে তা আপনাকে জানায়, ভবিষ্যতে লোকেরা নিজেরাই মাছ ধরতে সহায়তা করে।
রোব্যাটিকাস

2
@ রোব্যাটিকাস (এমনকি পরে কেন) আইএল দেখতে লাগে কারণ স্পেসিফিকেশনটি তাই বলে। সিনট্যাকটিক চিনির বিস্তৃতি (ওরফে ফোরাচ) হ'ল "ইন" এর ডান দিকের অভিব্যক্তিটি মূল্যায়ন GetEnumeratorকরা এবং ফলাফলটি কল করা
রুন এফএস

2
@ রুনএফএস - ঠিক স্পেসিফিকেশনটি বোঝা বা আইএলটির দিকে তাকানো "কেন কারণ" তা বের করার একটি উপায়। অথবা দুটি পৃথক সি # পদ্ধতির একই আইএল পর্যন্ত ফুটে উঠেছে কিনা তা মূল্যায়ন করতে। এটি মূলত উপরের শিমির প্রতি আমার বক্তব্য ছিল।
রোব্যাটিকাস

148

একটি foreachলুপ GetEnumeratorপদ্ধতিটি কল করে ।
তাহলে সংগ্রহ null, এই পদ্ধতি কল একটি ফলাফল NullReferenceException

nullসংগ্রহ ফিরিয়ে দেওয়া খারাপ অভ্যাস ; পরিবর্তে আপনার পদ্ধতিগুলি একটি খালি সংগ্রহ ফেরত দেওয়া উচিত।


7
আমি সম্মত, খালি সংগ্রহ সর্বদা ফিরে আসা উচিত ... তবে আমি এই পদ্ধতিগুলি লিখি না :)
পোলারিস 878

19
@ পোলারিস, শূন্য কোয়েলেসিং অপারেটরকে উদ্ধার করতে! int[] returnArray = Do.Something() ?? new int[] {};
জেএসবি ձոգչ

2
বা: ... ?? new int[0]
কেন

3
+1 শূন্য সংগ্রহের পরিবর্তে খালি সংগ্রহগুলি ফিরিয়ে দেওয়ার পরামর্শ মতো। ধন্যবাদ।
গ্যালিলিও

1
আমি একটি খারাপ অভ্যাসের সাথে একমত নই: দেখুন - যদি কোনও ফাংশন ব্যর্থ হয় তবে তা খালি সংগ্রহ ফিরিয়ে দিতে পারে - এটি কনস্ট্রাক্টরের কল, মেমরি বরাদ্দ, এবং সম্ভবত সম্পাদনের জন্য একটি কোডের একগুচ্ছ। হয় আপনি কেবল return নাল »return ফিরে আসতে পারেন স্পষ্টতই ফিরে আসার জন্য কেবল একটি কোড রয়েছে এবং চেক করার জন্য একটি খুব সংক্ষিপ্ত কোডটি আর্গুমেন্টটি হ'ল নাল» » এটি কেবল একটি পারফরম্যান্স।
হাই-এঞ্জেল

47

খালি সংগ্রহ এবং কোনও সংগ্রহের নাল রেফারেন্সের মধ্যে একটি বড় পার্থক্য রয়েছে।

আপনি যখন foreachঅভ্যন্তরীণভাবে ব্যবহার করেন তখন এটি আইইনিউমারেবলের getEnumerator () পদ্ধতি কল করে। যখন রেফারেন্সটি বাতিল হয়ে যায়, এটি এই ব্যতিক্রমটি বাড়িয়ে তুলবে।

যাইহোক, এটি খালি IEnumerableবা সম্পূর্ণরূপে বৈধ IEnumerable<T>। এই ক্ষেত্রে, ভবিষ্যদ্বাণী কোনও কিছুর উপরে "পুনরাবৃত্তি" করবে না (যেহেতু সংগ্রহটি খালি), তবে এটি নিক্ষেপও করবে না, কারণ এটি পুরোপুরি বৈধ দৃশ্য।


সম্পাদনা:

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

public static IEnumerable<T> AsNotNull<T>(this IEnumerable<T> original)
{
     return original ?? Enumerable.Empty<T>();
}

তারপরে আপনি কেবল কল করতে পারেন:

foreach (int i in returnArray.AsNotNull())
{
    // do some more stuff
}

3
হ্যাঁ, তবে কেন ভবিষ্যদ্বাণী করে গণনা করার আগে নাল চেক করবেন না?
পোলারিস 878

12
@ পোলারিস 878: কারণ এটি কখনই শূন্য সংগ্রহের সাথে ব্যবহারের উদ্দেশ্যে করা হয়নি। এটি, আইএমও, একটি ভাল জিনিস - যেহেতু নাল রেফারেন্স এবং খালি সংগ্রহকে আলাদাভাবে চিকিত্সা করা উচিত। আপনি যদি এটিকে ঘিরে কাজ করতে চান তবে উপায় আছে .. .আমি অন্য একটি বিকল্প দেখানোর জন্য সম্পাদনা করব ...
রিড কোপসি

1
@ পোলারিস ৮৮78: আমি আপনার প্রশ্নের পুনরায় রেকর্ডিংয়ের পরামর্শ দেব: "রানার সময়টি এনুমিরেটর পাওয়ার আগে কেন নালার পরীক্ষা করা উচিত?"
রিড কোপসি

আমার ধারণা আমি জিজ্ঞাসা করছি "কেন নয়?" লোল মনে হচ্ছে আচরণটি এখনও
ঠিকভাবে

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

12

এটি অনেক আগেই উত্তর দেওয়া হচ্ছে তবে আমি কেবল নাল পয়েন্টার ব্যতিক্রম এড়াতে নিম্নলিখিত পদ্ধতিতে এটি করার চেষ্টা করেছি এবং সি # নাল চেক অপারেটর ব্যবহারকারীর পক্ষে দরকারী হতে পারে?

     //fragments is a list which can be null
     fragments?.ForEach((obj) =>
        {
            //do something with obj
        });

@kjbartel আপনি এই দ্বারা এক বছর ধরে ( "এ বীট stackoverflow.com/a/32134295/401246 ")। ;) এটি সর্বোত্তম সমাধান, কারণ এটি হয় না: ক) nullপুরোপুরি লুপের এলসিডিতে সাধারণকরণ Enumerable(যেমনটি ব্যবহার করা ??হবে) এর সাধারণ সম্পাদনের সাথে জড়িত , খ) প্রতিটি প্রকল্পে এক্সটেনশন পদ্ধতি যুক্ত করা প্রয়োজন, এবং গ) null IEnumerableএর সাথে শুরু করতে এস (পিফফ্ট! পুহ-লেজ! এসএমএইচ।) এড়ানো দরকার ।
টম

10

এটিকে কাজে লাগানোর জন্য আরও একটি এক্সটেনশন পদ্ধতি:

public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
{
    if(items == null) return;
    foreach (var item in items) action(item);
}

বিভিন্ন উপায়ে গ্রহণ করুন:

(1) এমন একটি পদ্ধতি সহ যা গ্রহণ করে T:

returnArray.ForEach(Console.WriteLine);

(২) একটি অভিব্যক্তি সহ:

returnArray.ForEach(i => UpdateStatus(string.Format("{0}% complete", i)));

(3) বহুমুখী বেনাম পদ্ধতি সহ

int toCompare = 10;
returnArray.ForEach(i =>
{
    var thisInt = i;
    var next = i++;
    if(next > 10) Console.WriteLine("Match: {0}", i);
});

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

এমন দুর্দান্ত কোডের জন্য ধন্যবাদ, তবে আমি প্রথম পদ্ধতিগুলি বুঝতে পারি নি, কেন আপনি প্যারামিটার হিসাবে কনসোল.উইটলাইনটি পাস করেন, যদিও এটি অ্যারে উপাদানগুলি প্রিন্ট করে b তবে তা বুঝতে পারেনি
অজয় সিং

@ অজয়সিংহ Console.WriteLineহ'ল একটি পদ্ধতির উদাহরণ যা একটি যুক্তি ( আন Action<T>) গ্রহণ করে। আইটেম 1, 2 এবং 3 .ForEachএক্সটেনশন পদ্ধতিতে ফাংশনগুলি পাস করার উদাহরণ দেখায় ।
জে

@ kjbartel এর উত্তর ( "এ stackoverflow.com/a/32134295/401246 ", সবচেয়ে ভালো সমাধান, কারণ এটা না: ক) এর (এমনকি যখন না কর্মক্ষমতা অবনতি জড়িত null) এর এলসিডি পুরো লুপ সরলীকরণ Enumerable(ব্যবহার ??would ), খ) প্রতিটি প্রকল্পে একটি এক্সটেনশন পদ্ধতি যুক্ত করা প্রয়োজন, বা গ) null IEnumerableএর জন্য (পিএফফ্ট! পুহ-লেইজ! এসএমএইচ।) এড়ানো প্রয়োজন (কোজ, nullমানে এন / এ, যদিও খালি তালিকার অর্থ এটি অ্যাপ্লিকেশন। তবে এটি বর্তমানে, ভাল, খালি !, অর্থাত্ একটি এমপ্লিট। এমন কমিশন থাকতে পারে যা বিক্রয়হীন জন্য N / A বা বিক্রয়ের জন্য খালি)।
টম

5

আপনাকে সাহায্য করার জন্য কেবল একটি এক্সটেনশন পদ্ধতি লিখুন:

public static class Extensions
{
   public static void ForEachWithNull<T>(this IEnumerable<T> source, Action<T> action)
   {
      if(source == null)
      {
         return;
      }

      foreach(var item in source)
      {
         action(item);
      }
   }
}

5

কারণ নাল সংগ্রহটি খালি সংগ্রহের মতো জিনিস নয়। খালি সংগ্রহ হ'ল একটি উপাদান যা কোনও উপাদান ছাড়াই; একটি নাল সংগ্রহ একটি অস্তিত্বের অবজেক্ট।

এখানে চেষ্টা করার মতো কিছু রয়েছে: যে কোনও ধরণের দুটি সংগ্রহ ঘোষণা করুন। একটিকে সাধারণভাবে সূচনা করুন যাতে এটি খালি হয় এবং অন্যটির মান নির্ধারণ করে null। তারপরে উভয় সংকলনে একটি অবজেক্ট যুক্ত করার চেষ্টা করুন এবং দেখুন কী ঘটে।


3

এর দোষ Do.Something()। এখানে সর্বোত্তম অনুশীলন হ'ল শূন্যের পরিবর্তে 0 আকারের অ্যারেটি (এটি সম্ভব) return


2

কারণ পর্দার আড়ালে foreachএকটি সমকক্ষকে অর্জন করে, এর সমতুল্য:

using (IEnumerator<int> enumerator = returnArray.getEnumerator()) {
    while (enumerator.MoveNext()) {
        int i = enumerator.Current;
        // do some more stuff
    }
}

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

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

1
আমি তাই মনে করি না. পূর্বাভাসটি সংগ্রহের উপরে পরিচালনা করতে বোঝানো হয় এবং সরাসরি নাল বস্তুর উল্লেখের চেয়ে আলাদা। যদিও কেউ একই মত তর্ক করতে পারে, আমি বাজি ধরছি যদি আপনি বিশ্বের সমস্ত কোড বিশ্লেষণ করেন তবে আপনার কাছে বেশিরভাগ ফোরচ লুপের কাছে কেবল কোনও ধরণের নাল চেক থাকবে যখন সংগ্রহটি "নাল" হবে (যা হয়) সুতরাং খালি হিসাবে একই আচরণ করা)। আমি মনে করি না যে নাল সংগ্রহের উপরে কেউ লুপিংকে এমন কিছু হিসাবে বিবেচনা করে যা তারা পছন্দ করে এবং সংগ্রহটি যদি শূন্য থাকে তবে কেবল লুপটিকে উপেক্ষা করবে। হতে পারে, বরং, একটি পূর্বাচ? (সিআর মধ্যে var এক্স) ব্যবহার করা যেতে পারে।
অ্যাবস্ট্রাক্ট

মূলত আমি যে বিষয়টিটি তৈরির চেষ্টা করছি তা হ'ল এটি কোডটিতে কিছুটা জঞ্জাল তৈরি করে যেহেতু কোনও কারণ ছাড়াই প্রতিবারের জন্য চেক করতে হয়। অবশ্যই এক্সটেনশানগুলি কাজ করে তবে খুব বেশি সমস্যা ছাড়াই এগুলি এড়াতে একটি ভাষা বৈশিষ্ট্য যুক্ত করা যেতে পারে। (প্রধানত আমি মনে করি যে বর্তমান পদ্ধতিটি লুকানো বাগ তৈরি করে যেহেতু প্রোগ্রামার চেকটি রাখতে ভুলে যেতে পারে এবং তাই এটি একটি ব্যতিক্রম ... কারণ হয় তিনি লুপের আগে চেকটি অন্য কোথাও হওয়ার প্রত্যাশা করেছেন বা ভেবেছেন যে এটি প্রাক-সূচনা হয়েছিল) এটি হতে পারে বা পরিবর্তিত হতে পারে) তবে উভয় কারণে আচরণটি শূন্যের মতোই হবে
অ্যাবস্ট্রাক্ট

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

1

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

    var returnArray = DoSomething() ?? Enumerable.Empty<int>();

    foreach (int i in returnArray)
    {
        // do some more stuff
    }

এইভাবে আমরা সংগ্রহটি যতটা আমরা চাই ব্যতীত ভয় ছাড়াই ব্যবহার করতে পারি এবং আমরা অতিরিক্ত শর্তযুক্ত বিবৃতি দিয়ে কোডটিকে কলুষিত করি না।

নাল চেক অপারেটর ব্যবহার ?.করাও একটি দুর্দান্ত পন্থা। তবে, অ্যারের ক্ষেত্রে (প্রশ্নের উদাহরণের মতো), এটির আগে তালিকায় রূপান্তর করা উচিত:

    int[] returnArray = DoSomething();

    returnArray?.ToList().ForEach((i) =>
    {
        // do some more stuff
    });

2
ForEachকোনও কোডবেসে আমি ঘৃণা করি সেগুলির মধ্যে একটি পদ্ধতিতে কেবল অ্যাক্সেস পেতে কেবল তালিকায় রূপান্তর করা is
হাইস্টেনট্রু

আমি একমত ... আমি যতটা সম্ভব এড়ানো। :(
Alielson Piffer

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.