সি # তে নাল প্যারামিটার চেক করা হচ্ছে


88

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

void f(SomeType s)
{
  if (s == null)
  {
    throw new ArgumentNullException("s cannot be null.");
  }

  // Use s
}

13
আমি গুরুতরভাবে সন্দেহ করি যে একটি সাধারণ নাল চেক আপনার কোডকে একটি উল্লেখযোগ্য (বা এমনকি পরিমাপযোগ্য) পরিমাণে ধীরে ধীরে কমিয়ে দেবে।
হেইনজি

ঠিক আছে, এটি "ইউজ এস" কী করে তা নির্ভর করে। যদি এটি সমস্ত কিছু "রিটার্ন এস। সোমফিল্ড" হয় তবে অতিরিক্ত চেকটি সম্ভবত প্রশস্ততার ক্রম দ্বারা পদ্ধতিটি ধীর করবে।
ক্যালাস

11
@ ক্যালাস: সম্ভবত? সম্ভবত এটি আমার বইতে কাটেনি। আপনার পরীক্ষার ডেটা কোথায়? এবং সম্ভবত যে এই পরিবর্তনটি আপনার অ্যাপ্লিকেশনটির প্রথম স্থানে বাধা হয়ে দাঁড়াবে?
জন স্কিটি

@ জন: আপনি ঠিক বলেছেন আমার কাছে এখানে হার্ড ডেটা নেই। আপনি যদি উইন্ডোজ ফোন বা এক্সবক্সের জন্য বিকাশ করেন যেখানে জেআইটি ইনলাইনিং এই অতিরিক্ত "যদি" দ্বারা প্রভাবিত হবে এবং যেখানে শাখা প্রশস্তকরণ খুব ব্যয়বহুল, আপনি বেশ বিড়বিড় হতে পারেন।
ক্যালাস

4
@ ক্যালাস: সুতরাং আপনার কোড শৈলীর খুব নির্দিষ্ট ক্ষেত্রে এটি প্রমাণ করার পরে সামঞ্জস্য করুন যে এটি একটি তাত্পর্যপূর্ণ পার্থক্যের সৃষ্টি করে বা ডিবাগ ব্যবহার করে sএরসেট (আবার, কেবল সেই পরিস্থিতিতে, এরিকের উত্তর দেখুন) যাতে চেকগুলি কেবল নির্দিষ্ট কিছু বিল্ডে থাকে।
জন স্কিটি

উত্তর:


167

হ্যাঁ, এর ভাল কারণ রয়েছে:

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

এখন আপনার আপত্তি হিসাবে:

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

এবং আপনার দাবির জন্য:

স্পষ্টতই, যে কোডগুলি এস ব্যবহার করে তা কোনওভাবেই ব্যতিক্রম ছুঁড়ে ফেলবে।

সত্যি? বিবেচনা:

void f(SomeType s)
{
  // Use s
  Console.WriteLine("I've got a message of {0}", s);
}

এটি ব্যবহার করে sতবে এটি ব্যতিক্রম হয় না। যদি এটি বাতিল হয়ে যায় তবে এটি অবৈধ sএবং এটি ইঙ্গিত দেয় যে কিছু ভুল হয়েছে, একটি ব্যতিক্রম এখানে সর্বাধিক উপযুক্ত আচরণ।

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

একটি পার্শ্ব নোট: এর একক-প্যারামিটার কনস্ট্রাক্টর ওভারলোড ArgumentNullExceptionকেবলমাত্র প্যারামিটারের নাম হওয়া উচিত, সুতরাং আপনার পরীক্ষাটি হওয়া উচিত:

if (s == null)
{
  throw new ArgumentNullException("s");
}

বিকল্পভাবে আপনি কিছুটা সংযোজনকে মঞ্জুরি দিয়ে একটি এক্সটেনশন পদ্ধতি তৈরি করতে পারেন:

s.ThrowIfNull("s");

আমার (জেনেরিক) এক্সটেনশন পদ্ধতির সংস্করণে, আমি এটিকে মূল মানটি যদি নালাগুলি না দেয় তবে তা ফিরিয়ে আনব, যাতে আপনাকে এই জাতীয় জিনিস লিখতে দেয়:

this.name = name.ThrowIfNull("name");

আপনার যদি খুব বেশি বিরক্ত না হয় তবে আপনার একটি ওভারলোডও থাকতে পারে যা প্যারামিটারের নাম নেয় না।


8
এক্সটেনশন পদ্ধতির জন্য +1। আমি সঠিক একই জিনিস কাজ করেছি যেমন অন্যান্য বৈধতা সহ ThrowIfEmptyউপরICollection
Davy8

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

8
@ ক্যালাস: আপনি কি পরীক্ষার ক্ষেত্রে একই মনোভাবটি প্রয়োগ করেন? "আমার পরীক্ষাগুলি সমস্ত সম্ভাব্য বাগগুলি ধরবে না, সুতরাং আমি কোনও লিখব না"? নিরাপত্তা প্রক্রিয়া যখন না কাজ, তারা সহজে সমস্যা খুঁজে বার করতে সেটিতে এবং অন্যত্র প্রভাব কমাতে (আগে সমস্যা সংক্রামক দ্বারা) করব। যদি এটি 10 ​​এর মধ্যে 9 বার হয়ে থাকে, তবে এটি 10 ​​এর মধ্যে 0 বার হওয়ার চেয়ে এখনও ভাল ...
জন স্কিট

4
@ ডক্টরওরিও: আমি ব্যবহার করি না Debug.Assert। উত্পাদনের ত্রুটিগুলি ধরা (এমনকি তারা সত্যিকারের ডেটা স্ক্রু করার আগে) উন্নয়নের চেয়ে বেশি গুরুত্বপূর্ণ।
জন স্কিটি

4
এখন সি # 6.0 এর সাথে আমরা এমনকি ব্যবহার করতে পারি throw new ArgumentNullException(nameof(s))
hrzafer

52

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

সুস্পষ্ট নাল চেকগুলি কখন যুক্ত করতে হবে সে সম্পর্কে আমার মনোভাব এই চত্বরের উপর ভিত্তি করে:

  • আপনার ইউনিট পরীক্ষার জন্য একটি প্রোগ্রামে প্রতিটি বিবৃতি অনুশীলন করার উপায় থাকতে হবে।
  • throwবিবৃতি বিবৃতি
  • একটি এর পরিণতি ifএকটি বিবৃতি
  • অতএব, ব্যায়াম একটি উপায় থাকা উচিত throwমধ্যেif (x == null) throw whatever;

যদি বিবৃতিটি কার্যকর করার কোনও সম্ভাব্য উপায় না থাকে তবে এটি পরীক্ষা করা যায় না এবং এটি দিয়ে প্রতিস্থাপন করা উচিত Debug.Assert(x != null);

যদি বিবৃতিটি কার্যকর করার কোনও সম্ভাব্য উপায় থাকে তবে বিবৃতিটি লিখুন এবং তারপরে এমন একটি ইউনিট পরীক্ষা লিখুন যা এটি অনুশীলন করে।

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

বিপরীতে, ব্যক্তিগত ধরণের ব্যক্তিগত পদ্ধতিগুলি এমন পরিস্থিতিতে হওয়ার সম্ভাবনা বেশি থাকে যেখানে আপনি যুক্তিগুলি নিয়ন্ত্রণ করেন এবং যুক্তিটি কখনই বাতিল হয় না তার দৃ guarantee় গ্যারান্টি থাকতে পারে; যে আক্রমণকারী ডকুমেন্ট করতে একটি দৃ as়তা ব্যবহার করুন।


23

আমি এখন এক বছর ধরে এটি ব্যবহার করছি:

_ = s ?? throw new ArgumentNullException(nameof(s));

এটি একটি অনেলাইনার এবং বাতিল ( _) এর অর্থ হ'ল কোনও অপ্রয়োজনীয় বরাদ্দ নেই।


8

সুস্পষ্ট ifচেক ছাড়া এটি কী ছিল তা নির্ধারণ করা খুব কঠিন হতে পারেnull না করে, কোডটি নিজের না রাখলে ।

পেলে ক NullReferenceException সোর্স কোড ব্যতীত কোনও লাইব্রেরির ভিতরে থেকে গভীরভাবে কী ভুল করেছেন তা নির্ধারণ করতে আপনার অনেক সমস্যা হতে পারে।

এই ifচেকগুলি আপনার কোড লক্ষণীয়ভাবে ধীর করে দেবে না।


নোট করুন ArgumentNullExceptionকনস্ট্রাক্টরের প্যারামিটারটি একটি প্যারামিটারের নাম, কোনও বার্তা নয়।
আপনার কোড হওয়া উচিত

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

এটিকে আরও সহজ করতে আমি একটি কোড স্নিপেট লিখেছি:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>Check for null arguments</Title>
            <Shortcut>tna</Shortcut>
            <Description>Code snippet for throw new ArgumentNullException</Description>
            <Author>SLaks</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
                <SnippetType>SurroundsWith</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>Parameter</ID>
                    <ToolTip>Paremeter to check for null</ToolTip>
                    <Default>value</Default>
                </Literal>
            </Declarations>
            <Code Language="csharp"><![CDATA[if ($Parameter$ == null) throw new ArgumentNullException("$Parameter$");
        $end$]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

5

আপনি যদি প্যারামিটার হিসাবে কোনও নাল বস্তু না পেয়ে থাকেন তা নিশ্চিত করার জন্য যদি আপনার আরও ভাল উপায়ের প্রয়োজন হয় তবে আপনি কোড চুক্তিগুলি একবার দেখে নিতে পারেন।


2

মূল সুবিধাটি হ'ল আপনি প্রথম থেকেই আপনার পদ্ধতির প্রয়োজনীয়তার সাথে সুস্পষ্ট হয়ে যাচ্ছেন। কোডে কাজ করা অন্যান্য বিকাশকারীদের দ্বারা এটি স্পষ্ট হয়ে যায় যে একজন কলকারী আপনার পদ্ধতির নাল মান প্রেরণ করা সত্যই এটি একটি ত্রুটি।

অন্য কোনও কোড কার্যকর করার আগে এই চেকটিও পদ্ধতিটির কার্যকারিতা থামিয়ে দেবে। এর অর্থ আপনাকে অসম্পূর্ণ রেখে যাওয়া পদ্ধতিটির দ্বারা পরিবর্তনগুলি নিয়ে চিন্তা করতে হবে না।


2

আপনি যখন ব্যতিক্রমটিকে আঘাত করেন তখন এটি কিছুটা ডিবাগিং সাশ্রয় করে।

আর্গুমেন্টনাল এক্সসেপশন স্পষ্টভাবে বলে যে এটি "s" যা নাল ছিল।

যদি আপনার সেই চেকটি না থাকে এবং কোডটি ফুটিয়ে উঠতে দেয় তবে আপনি সেই পদ্ধতিতে কিছু অজানা লাইন থেকে একটি নুলারফেরান এক্সেক্সপেশন পান। একটি রিলিজ বিল্ডে আপনি লাইন নম্বর পাবেন না!


0

আসল কোড:

void f(SomeType s)
{
  if (s == null)
  {
    throw new ArgumentNullException("s cannot be null.");
  }

  // Use s
}

এটি আবার লিখুন:

void f(SomeType s)
{
  if (s == null) throw new ArgumentNullException(nameof(s));
}

ব্যবহার করে পুনর্লিখনের কারণ nameofহ'ল এটি সহজ রিফ্যাক্টরিংয়ের জন্য অনুমতি দেয়। যদি আপনার ভেরিয়েবলের নাম যদি sকখনও পরিবর্তিত হয়, তবে ডিবাগিং বার্তাগুলিও আপডেট করা হবে, আপনি যদি কেবলমাত্র ভেরিয়েবলটির নাম হার্ডকোড করে থাকেন তবে সময়ের সাথে সাথে আপডেটগুলি করা হলে তা শেষ পর্যন্ত পুরানো হয়ে যাবে। এটি শিল্পে ব্যবহৃত একটি ভাল অনুশীলন।


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