নাল রেফারেন্স সম্ভব বলে মনে হচ্ছে না, কেন আমরা সম্ভাব্য বিন্দু নাল রেফারেন্স সতর্কতা পেতে পারি?


9

এইচএনকিউতে এই প্রশ্নটি পড়ে , আমি সি # 8 তে নুলযোগ্য রেফারেন্স প্রকারগুলি সম্পর্কে পড়তে গিয়ে কিছু পরীক্ষা-নিরীক্ষা করেছি made

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

#nullable enable
class Program
{
    static void Main()
    {
        var s = "";
        var b = s == null; // If you comment this line out, the warning on the line below disappears
        var i = s.Length; // warning CS8602: Dereference of a possibly null reference
    }
}

উপরের সাথে সংযুক্ত ডকুমেন্টেশন পড়ার পরে, আমি s == nullলাইনটি আমাকে একটি সতর্কতা দেওয়ার আশা করব - সর্বোপরি sস্পষ্টভাবে অ-অযোগ্য, সুতরাং এটির সাথে তুলনা করা nullকোনও মানে হয় না।

পরিবর্তে, আমি পরের লাইনে একটি সতর্কতা পাচ্ছি , এবং সতর্কতাটি বলেছে যে sএটি একটি নাল রেফারেন্স সম্ভব, যদিও এটি একটি মানুষের পক্ষে, এটি স্পষ্টতই তা নয়।

আরও বেশি, সতর্কতা প্রদর্শিত হয় না যদি আমরা তুলনা sনা করি null

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

একটি নতুন গিটহাব ইস্যু তৈরি করার পরিবর্তে এবং অবিশ্বাস্যরকম ব্যস্ত প্রকল্পের অবদানকারীদের সময় গ্রহণের পরিবর্তে, আমি এটি সম্প্রদায়ের কাছে রাখছি।

আপনি দয়া করে আমাকে ব্যাখ্যা করতে পারেন যে কি হচ্ছে এবং কেন? বিশেষত, কেন s == nullলাইনে কোনও সতর্কতা তৈরি করা হয় নি , এবং CS8602যখন এটি nullএখানে উল্লেখ করা সম্ভব বলে মনে হয় না কেন আমরা কেন করি ? লিঙ্কযুক্ত গিটহাব থ্রেডের পরামর্শ অনুসারে যদি ন্যূবিলিটি অনুমানটি বুলেট-প্রুফ না হয় তবে কীভাবে এটি ভুল হতে পারে? এর কিছু উদাহরণ কী হবে?


দেখে মনে হয় যে সংকলক নিজেই আচরণ সেট করে যে এই মুহুর্তে চলক "s" নਾਲ হতে পারে। যাইহোক, আমি যদি কখনও স্ট্রিং বা অবজেক্ট ব্যবহার করি তবে আপনি কোনও ফাংশন কল করার আগে সর্বদা একটি চেক থাকা উচিত। "গুলি?। দৈর্ঘ্য" এর কৌশলটি করা উচিত এবং সতর্কতা নিজেই অদৃশ্য হয়ে যায়।
chg

1
@ সিএইচজি, এর দরকার নেই ?কারণ sএটি অযোগ্য নয়। এটি নালায় পরিণত হয় না, কেবল কারণ আমরা এর সাথে তুলনা করার জন্য যথেষ্ট নির্বোধ ছিল null
অ্যান্ড্রু সাভিনিখ

আমি পূর্বের প্রশ্নটি অনুসরণ করছিলাম (দুঃখিত, এটি খুঁজে পাচ্ছে না) যেখানে এটি পোস্ট করা হয়েছিল যে আপনি যদি কোনও মান নাল বলে চেক যুক্ত করেন তবে সংকলকটি 'ইঙ্গিত' হিসাবে গ্রহণ করে যে মানটি নাল হতে পারে, এমনকি যদি প্রদর্শিত হয় না।
শে

@ স্টুয়ার্ট, হ্যাঁ, এটি মনে হচ্ছে এটি। সুতরাং এখন প্রশ্ন: কেন এটি দরকারী?
অ্যান্ড্রু সাভিনিখ

1
@ সিএজিজি, আচ্ছা, আমি যা প্রশ্নোত্তর বলি, তাই না?
অ্যান্ড্রু সাভিনিখ

উত্তর:


7

এটি কার্যকরভাবে উত্তরটির ডুপ্লিকেট যা @ স্টুয়ার্টড লিঙ্ক করেছে, সুতরাং আমি এখানে সুপার গভীর গভীরতায় যেতে যাচ্ছি না। তবে বিষয়টির মূলটি হ'ল এটি কোনও ভাষা বাগ বা সংকলক বাগ নয়, এটি ঠিক বাস্তবায়িত হওয়ার মতো আচরণের উদ্দেশ্যে। আমরা একটি ভেরিয়েবলের নাল অবস্থা ট্র্যাক করি। আপনি যখন প্রাথমিকভাবে ভেরিয়েবলটি ঘোষণা করেন, তখন সেই অবস্থা নটনুল হয় কারণ আপনি স্পষ্টভাবে এটিকে এমন কোনও মান দিয়ে শুরু করেন যা শূন্য নয়। কিন্তু আমরা নটনুলটি কোথা থেকে এসেছে তা ট্র্যাক করি না। এটি উদাহরণস্বরূপ কার্যকরভাবে সমতুল্য কোড:

#nullable enable
class Program
{
    static void Main()
    {
        M("");
    }
    static void M(string s)
    {
        var b = s == null;
        var i = s.Length; // warning CS8602: Dereference of a possibly null reference
    }
}

উভয় ক্ষেত্রেই, আপনি স্পষ্টভাবে sজন্য পরীক্ষা null। ম্যাডস যেমন এই প্রশ্নের জবাব দিয়েছেন ঠিক তেমনই আমরা এটিকে প্রবাহ বিশ্লেষণের ইনপুট হিসাবে গ্রহণ করি: https://stackoverflow.com/a/59328672/2672518 । এই উত্তরে, ফলাফলটি আপনি ফিরে আসার বিষয়ে একটি সতর্কতা পান warning এই ক্ষেত্রে, উত্তরটি হ'ল আপনি একটি সতর্কতা পেয়েছেন যে আপনি সম্ভবত নাল রেফারেন্সটিকে সম্মানিত করেছেন।

এটি নালায় পরিণত হয় না, কেবল কারণ আমরা এর সাথে তুলনা করার জন্য যথেষ্ট নির্বোধ ছিল null

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


ধন্যবাদ. এটি বেশিরভাগই অন্যান্য প্রশ্নের সাথে মিলগুলিকে সম্বোধন করে, আমি পার্থক্যগুলিকে আরও সম্বলিত করতে চাই। উদাহরণস্বরূপ, কেন s == nullএকটি সতর্কতা উত্পন্ন হয় না?
অ্যান্ড্রু সাভিনিখ

এছাড়াও আমি বুঝতে পেরেছি যে সাথে #nullable enable; string s = "";s = null;সংকলন এবং কাজ (এটি এখনও একটি সতর্কবার্তা উত্পন্ন করে) এমন কী কী সুবিধা রয়েছে, যেগুলি বাস্তবায়িত নাল এনটোটেশন প্রসঙ্গে "নন-রেলেবল রেফারেন্স" -কে নাল বরাদ্দ করার অনুমতি দেয়?
অ্যান্ড্রু সাভিনিখ

ম্যাড এর উত্তর এই বিষয়টিকে কেন্দ্র করে যে "[সংকলক] পৃথক ভেরিয়েবলের রাষ্ট্রের মধ্যে সম্পর্ককে ট্র্যাক করে না" এই উদাহরণে আমাদের পৃথক ভেরিয়েবল নেই, সুতরাং ম্যাডের বাকী উত্তরগুলি এই ক্ষেত্রে প্রয়োগ করতে আমার সমস্যা হয়।
অ্যান্ড্রু সাভিনিখ

এটা বলার অপেক্ষা রাখে না, তবে মনে আছে, আমি এখানে সমালোচনা করার জন্য নয়, শিখতে চাইছি। 2001 সালে এটি প্রথম প্রকাশের সময় থেকেই আমি সি # ব্যবহার করে আসছি I'm যদিও আমি ভাষায় নতুন নই, সংকলকটি যেভাবে আচরণ করে তা আমার জন্য অবাক করেছিল। এই প্রশ্নের লক্ষ্য হ'ল এই আচরণটি কেন মানুষের পক্ষে কার্যকর।
অ্যান্ড্রু সাভিনিখ

যাচাই করার জন্য বৈধ কারণ রয়েছে s == null। সম্ভবত, উদাহরণস্বরূপ, আপনি একটি সর্বজনীন পদ্ধতিতে আছেন এবং আপনি পরামিতি যাচাই করতে চান। অথবা, আপনি সম্ভবত একটি লাইব্রেরি ব্যবহার করছেন যা ভুলভাবে টীকাযুক্ত করা হয়েছে, এবং যতক্ষণ না তারা এই বাগটি ঠিক করে দেয় আপনি নালার সাথে ডিল করতে হবে যেখানে এটি ঘোষিত হয়নি। এই দুটি ক্ষেত্রেই যদি আমরা সতর্ক করে দিই তবে এটি একটি খারাপ অভিজ্ঞতা হবে be অ্যাসাইনমেন্টের অনুমতি দেওয়ার ক্ষেত্রে: স্থানীয় পরিবর্তনশীল টীকাগুলি কেবল পড়ার জন্য। এগুলি রানটাইমকে মোটেও প্রভাবিত করে না। প্রকৃতপক্ষে, আমরা এই সমস্ত সতর্কতাগুলি একটি একক ত্রুটি কোডে রেখেছি যাতে আপনি কোড মন্থন কমাতে চাইলে সেগুলি বন্ধ করতে পারেন।
333fred

0

যদি অযোগ্যতা অনুমান বুলেট-প্রুফ না হয়, [..] কীভাবে এটি ভুল হতে পারে?

আমি খুশি হয়ে সি # 8 এর অবর্ণনীয় রেফারেন্সগুলি উপলভ্য হওয়ার সাথে সাথেই গ্রহণ করেছিলাম। যেহেতু আমি রিশার্পারের [নটনুল] (ইত্যাদি) স্বরলিপি ব্যবহার করতে ব্যবহৃত হয়েছিলাম, তাই আমি উভয়ের মধ্যে কিছু পার্থক্য লক্ষ্য করেছি।

সি # সংকলকটি বোকা বানানো যেতে পারে তবে এটি সাবধানতার দিকে ভুল করে (সাধারণত, সর্বদা নয়)।

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

  • নাল মাফ করা নাল । প্রায়শই সম্মোহনের সতর্কতা এড়ানোর জন্য ব্যবহৃত হয় তবে অবজেক্টটিকে অযোগ্য করে রাখা হয়। দেখে মনে হচ্ছে আপনার পা দুটি জুতোতে রাখতে চাইছে।
    string s = null!; //No warning

  • পৃষ্ঠতল বিশ্লেষণ । রিশার্পারের বিরোধিতা করে (এটি কোড টীকাটি ব্যবহার করে এটি করে ), সি # সংকলক এখনও ননাল রেফারেন্সগুলি হ্যান্ডেল করার জন্য সম্পূর্ণ পরিসরের বৈশিষ্ট্য সমর্থন করে না।
    void DoSomethingWith(string? s)
    {    
        ThrowIfNull(s);
        var split = s.Split(' '); //Dereference warning
    }

যদিও এটি অযোগ্যতার জন্য যা কিছু সতর্কতা থেকে মুক্তি পেয়েছে তা পরীক্ষা করতে কিছু নির্মাণ ব্যবহার করার অনুমতি দেয়:

    public static void DoSomethingWith(string? s)
    {
        Debug.Assert(s != null, nameof(s) + " != null");
        var split = s.Split(' ');  //No warning
    }

বা (এখনও বেশ দুর্দান্ত) বৈশিষ্ট্য (এগুলি এখানে এখানে সন্ধান করুন ):

    public static bool IsNullOrEmpty([NotNullWhen(false)] string? value)
    {
        ...
    }

  • সংবেদনশীল কোড বিশ্লেষণ । এটিই আপনি প্রকাশ্যে এনেছিলেন। সংকলকটিকে কাজ করার জন্য অনুমান করা উচিত এবং কখনও কখনও এগুলি পাল্টা স্বজ্ঞাত বলে মনে হয় (মানুষের পক্ষে, কমপক্ষে)।
    void DoSomethingWith(string s)
    {    
        var b = s == null;
        var i = s.Length; // Dereference warning
    }

  • জেনেরিক নিয়ে ঝামেলা । জানতে চাইলে এখানে ও খুব ভাল ব্যাখ্যা এখানে (আগে, অনুচ্ছেদ "টি সমস্যাটির?" হিসাবে একই নিবন্ধ)। জেনেরিক্স জটিল কারণ তাদের উল্লেখ এবং মান উভয়ই খুশি করতে হয়। মূল পার্থক্যটি হ'ল যখন string?কেবল একটি স্ট্রিং থাকে, এ int?হয়ে যায় Nullable<int>এবং সংকলকটিকে তাদের বিভিন্নভাবে হ্যান্ডেল করতে বাধ্য করে। এছাড়াও এখানে, সংকলকটি নিরাপদ পথটি বেছে নিচ্ছে, আপনাকে কী প্রত্যাশা করছেন তা নির্দিষ্ট করতে বাধ্য করে:
    public interface IResult<out T> : IResult
    {
        T? Data { get; } //Warning/Error: A nullable type parameter must be known to be a value type or non-nullable reference type.
    }

বাধা দেওয়ার সমাধান:

    public interface IResult<out T> : IResult where T : class { T? Data { get; }}
    public interface IResult<T> : IResult where T : struct { T? Data { get; }}

তবে আমরা যদি সীমাবদ্ধতা ব্যবহার না করে ''? ডেটা থেকে, আমরা এখনও এটি 'ডিফল্ট' কীওয়ার্ড ব্যবহার করে নাল মান রাখতে সক্ষম হয়েছি:

    [Pure]
    public static Result<T> Failure(string description, T data = default)
        => new Result<T>(ResultOutcome.Failure, data, description); 
        // data here is definitely null. No warning though.

শেষটি আমার কাছে কৌতুকময় বলে মনে হচ্ছে, কারণ এটি অনিরাপদ কোডটি লেখার অনুমতি দেয়।

আশা করি এটি কাউকে সাহায্য করবে।


আমি অযোগ্য বৈশিষ্ট্যগুলিকে একটি পড়ার জন্য ডকগুলি দেওয়ার পরামর্শ দিই: ডকস.মাইক্রোসফট.ফেন / ডটনেট / সিএসআরপি / নন্যাবল- অ্যাট্রিবিউটস । তারা আপনার কিছু সমস্যা সমাধান করবে, বিশেষত পৃষ্ঠ বিশ্লেষণ বিভাগ এবং জেনেরিকগুলির সাথে।
333fred

লিঙ্কের জন্য ধন্যবাদ 333fred। যদিও আপনি খেলতে পারেন এমন বৈশিষ্ট্য রয়েছে, এমন একটি বৈশিষ্ট্য যা আমার পোস্ট করা সমস্যার সমাধান করে (এমন কিছু যা আমাকে বলে যে ThrowIfNull(s);আমাকে আশ্বাস দিচ্ছে যে sনাল নয়) বিদ্যমান নেই। এছাড়াও নিবন্ধটি নন- নাল জেনারিকগুলি কীভাবে পরিচালনা করতে হবে সে সম্পর্কেও বর্ণনা করা হয়েছে , যখন আমি দেখছিলাম যে আপনি কীভাবে সংকলককে "বোকা" বানাতে পারেন, নাল মান থাকলেও এটি সম্পর্কে কোনও সতর্কতা নেই।
অ্যালভিন সার্তর

আসলে, বৈশিষ্ট্যটির অস্তিত্ব নেই। এটি যুক্ত করতে আমি ডক্সে একটি বাগ দায়ের করেছি। আপনি খুঁজছেন DoesNotReturnIf(bool)
333fred

@ 333fred আসলে আমি আরও কিছু এরকম খুঁজছি DoesNotReturnIfNull(nullable)
অ্যালভিন সার্তোর 8:57
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.