সি # 8 নন-অযোগ্য রেফারেন্স এবং ট্রাই প্যাটার্ন


23

সি # ক্লাসে একটি প্যাটার্ন রয়েছে যার দ্বারা অনুকরণীয় : Dictionary.TryGetValueএবং int.TryParseএমন একটি পদ্ধতি যা একটি বুলিয়ান প্রদান করে যা অপারেশনের সাফল্য এবং আসল ফলাফল সহ একটি আউট প্যারামিটার নির্দেশ করে; যদি অপারেশন ব্যর্থ হয় তবে আউট প্যারামিটারটি বাতিল হয়ে যায়।

ধরে নেওয়া যাক আমি সি # 8 নন-অযোগ্য রেফারেন্স ব্যবহার করছি এবং আমার নিজের ক্লাসের জন্য ট্রাইপার্স পদ্ধতি লিখতে চাই। সঠিক স্বাক্ষর হল:

public static bool TryParse(string s, out MyClass? result);

ফলটি মিথ্যা ক্ষেত্রে নালার কারণে আউট ভেরিয়েবলকে অবশ্যই নাল হিসাবে চিহ্নিত করতে হবে।

যাইহোক, চেষ্টা প্যাটার্নটি সাধারণত এটির মতো ব্যবহৃত হয়:

if (MyClass.TryParse(s, out var result))
{
  // use result here
}

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

if (MyClass.TryParse(s, out var result))
{
  Console.WriteLine("Look: {0}", result.SomeProperty); // compiler warning, could be null
  Console.WriteLine("Look: {0}", result!.SomeProperty); // need override
}

এটি কুৎসিত এবং কিছুটা অপ্রয়োজনীয়।

সাধারণ ব্যবহারের ধরণটির কারণে আমার কাছে আরও একটি বিকল্প রয়েছে: ফলাফলের প্রকারটি সম্পর্কে মিথ্যা বলা:

public static bool TryParse(string s, out MyClass result) // not nullable
{
   // Happy path sets result to non-null and returns true.
   // Error path does this:
   result = null!; // override compiler complaint
   return false;
}

এখন সাধারণ ব্যবহার সুন্দর হয়ে উঠেছে:

if (MyClass.TryParse(s, out var result))
{
  Console.WriteLine("Look: {0}", result.SomeProperty); // no warning
}

কিন্তু অ্যাটিক্যাল ব্যবহারের সতর্কতাটি এটি পায় না:

else
{
  Console.WriteLine("Fail: {0}", result.SomeProperty);
  // Yes, result is in scope here. No, it will never be non-null.
  // Yes, it will throw. No, the compiler won't warn about it.
}

এখন আমি কোন পথে যাব তা নিশ্চিত নই। সি # ভাষা দল থেকে কোনও অফিসিয়াল সুপারিশ রয়েছে কি? ইতিমধ্যে এমন কোনও কোরএফএক্স কোড কি অ-অযোগ্য রেফারেন্সে রূপান্তরিত হয়েছে যা আমাকে কীভাবে এটি করতে পারে তা দেখিয়ে দিতে পারে? (আমি TryParseপদ্ধতিগুলি অনুসন্ধান করতে গিয়েছিলাম । IPAddressএটি একটি শ্রেণি যা একটি রয়েছে তবে এটি কোরফেক্সের মাস্টার শাখায় রূপান্তরিত হয়নি))

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


এটি চেষ্টা করে দেখেনি (এই কারণেই আমি এটি উত্তর হিসাবে লিখছি না), তবে স্যুইচ স্টেটমেন্টগুলির নতুন প্যাটার্নের সাথে মেলে বৈশিষ্ট্যটি সহ, আমি অনুমান করছি যে একটি বিকল্প হ'ল নলযোগ্য রেফারেন্স (কোনও চেষ্টা-বিন্যাস, ফিরে MyClass?আসুন, এবং এ case MyClass myObj:এবং (একটি বিকল্প) দিয়ে এটিতে একটি স্যুইচ করুন case null:
ফিলিপ মিলোভানোভিć

+1 আমি এই প্রশ্নটি সত্যিই পছন্দ করি এবং এটি নিয়ে কাজ করতে গিয়ে আমি সর্বদা ওভাররাইডের পরিবর্তে কেবলমাত্র অতিরিক্ত নাল চেক ব্যবহার করেছি - যা সর্বদা কিছুটা অপ্রয়োজনীয় এবং অকার্যকর মনে হয়েছিল, তবে এটি কখনও সম্পাদনমূলক সমালোচনামূলক কোডে ছিল না সুতরাং আমি এটি যেতে দেওয়া। এটি পরিচালনা করার একটি ক্লিনার উপায় আছে কিনা তা দেখে ভাল লাগবে!
ব্রায়ানএইচ

উত্তর:


10

বুল / আউট-ভেরি প্যাটার্নটি আপনি যেভাবে বর্ণনা করেছেন তেমন অযোগ্য রেফারেন্স ধরণের সাথে ভাল কাজ করে না। তাই সংকলকটির সাথে লড়াই করার পরিবর্তে জিনিসগুলি সহজ করার জন্য বৈশিষ্ট্যটি ব্যবহার করুন। সি # 8 এর উন্নত প্যাটার্ন মেলানো বৈশিষ্ট্যগুলিকে নিক্ষেপ করুন এবং আপনি একটি "দরিদ্র লোকের সম্ভবত টাইপ করুন" হিসাবে একটি প্রবণতা উল্লেখ করতে পারেন:

public static MyClass? TryParse(string s) => 



if (TryParse(someString) is {} myClass)
{
    // myClass wasn't null, we are good to use it
}

এইভাবে, আপনি outপ্যারামিটারগুলির সাথে ঘোরাঘুরি এড়াবেন এবং nullঅ-অযোগ্য রেফারেন্সের সাথে মিশ্রণের বিষয়ে আপনাকে সংকলকটির সাথে লড়াই করতে হবে না ।

এবং জেনেরিক কোডটি এর Dictionary.TryGetValueসাথে কীভাবে আচরণ করে ?

এই মুহুর্তে, "গরিব লোকটি হয়ত টাইপ" পড়ে যায়। আপনি যে চ্যালেঞ্জের মুখোমুখি হবেন তা হ'ল নোলযোগ্য রেফারেন্স প্রকারগুলি (এনআরটি) ব্যবহার করার সময়, সংকলকটি Foo<T>অ-অযোগ্য হিসাবে বিবেচনা করবে । তবে চেষ্টা করুন এবং এটিকে পরিবর্তন করুন এবং এটি Foo<T?>চাইবে যে Tকোনও শ্রেণি বা কাঠামোর মধ্যে আবদ্ধ হওয়া যেমন মূল্যহীন মান ধরণের হিসাবে সিএলআর এর দৃষ্টিভঙ্গি থেকে খুব আলাদা জিনিস। এর বিভিন্ন ধরণের কাজের আশপাশ রয়েছে:

  1. এনআরটি বৈশিষ্ট্যটি সক্ষম করবেন না,
  2. প্যারামিটারগুলির জন্য default(বরাবর !) ব্যবহার শুরু করুন outযদিও আপনার কোডটি কোনও নালিতে সাইন আপ করছে না,
  3. একটি বাস্তব ব্যবহার করুন Maybe<T>ফেরত মান, যা কখনো হয় টাইপ nullএবং গোপন যে boolএবং out Tমধ্যে HasValueএবং Valueবৈশিষ্ট্য অথবা কিছু যেমন
  4. একটি টিপল ব্যবহার করুন:
public static (bool success, T result) TryParse<T>(string s) => 


if (TryParse<MyClass>(someString) is (true, var result))
{
    // result is valid here, as success is true
}

আমি ব্যক্তিগতভাবে ব্যবহারের পক্ষে করছি Maybe<T>তবে এটি একটি ডিকনস্ট্রাক্টকে সমর্থন করছে যাতে এটি উপরের 4 হিসাবে টিপল হিসাবে প্যাটার্নটি মিলতে পারে।


2
TryParse(someString) is {} myClass- এই বাক্য গঠনটি কিছুটা অভ্যস্ত হয়ে উঠবে, তবে আমি ধারণাটি পছন্দ করি।
সেবাস্তিয়ান রেডল

TryParse(someString) is var myClassআমার কাছে সহজ দেখাচ্ছে
অলিভিয়ার জ্যাকট-ডেসকোম্বেস

2
@ অলিভিয়ার জাকোট-ডেসকোম্বস এটি দেখতে আরও সহজ দেখাচ্ছে ... তবে এটি কার্যকর হবে না। গাড়ির প্যাটার্নটি সর্বদা মেলে, তাই নাল x is var yহোক xবা না থাকুক তাই সর্বদা সত্য হবে ।
ডেভিড আরনো

15

আপনি একটু দেরী, আমার মত এই এ আসার থাকেন, তবে এটি সক্রিয় আউট .NET দল মত পরামিতি বৈশিষ্ট্যাবলী একটি গুচ্ছ মাধ্যমে এটি সুরাহা MaybeNullWhen(returnValue: true)মধ্যে System.Diagnostics.CodeAnalysisস্থান যা আপনি চেষ্টা প্যাটার্ন জন্য ব্যবহার করতে পারেন।

উদাহরণ স্বরূপ:

অভিধানের মতো জেনেরিক কোডটি কীভাবে চেষ্টা করে? ট্রাইগেটভ্যালু এটিকে মোকাবেলা করে?

bool TryGetValue(TKey key, [MaybeNullWhen(returnValue: false)] out TValue value);

যার অর্থ আপনি যদি এটির জন্য চেক না করেন তবে আপনাকে চিৎকার দেওয়া হবে true

// This is okay:
if(myDictionary.TryGetValue("cheese", out var result))
{
  var more = result * 42;
}

// But this is not:
_ = myDictionary.TryGetValue("cheese", out var result);
var more = result * 42;
// "CS8602: Dereference of a potentially null reference"

আরো বিস্তারিত বিবরণ:


3

আমি মনে করি না যে এখানে কোনও বিরোধ আছে।

আপনার আপত্তি

public static bool TryParse(string s, out MyClass? result);

হয়

যেহেতু আমি কেবল তখন শাখায় প্রবেশ করি যখন অপারেশন সফল হয়, ফলাফলটি কখনই সেই শাখায় শূন্য হয় না।

তবে, বাস্তবে পুরানো স্টাইলের ট্রাইপার্স ফাংশনে আউট প্যারামিটারে নাল দেওয়ার কার্যকারিতা রোধ করার কিছুই নেই।

যেমন।

MyJsonObject.TryParse("null", out obj) //sets obj to a null MyJsonObject and returns true

প্রোগ্রামার যখন তারা পরীক্ষা না করে আউট প্যারামিটার ব্যবহার করে তখন সতর্কতাটি সঠিক। আপনার চেক করা উচিত!

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

MyClass? x = (new List<MyClass>()).FirstOrDefault(i=>i==1);

এটির কোড দেওয়ার অ-ননীয় উপায় একটি ব্যতিক্রম ছুঁড়ে ফেলবে যেখানে সেখানে শূন্য থাকত। আপনার পার্সিং, পাওয়ার বা ফার্স্ট কিনা

MyClass x = (new List<MyClass>()).First(i=>i==1);

আমি মনে করি না FirstOrDefault, তুলনা করা যেতে পারে কারণ এর ফেরত মান এর nullness হয় মূল সংকেত। ইন TryParseপদ্ধতি, যদি ফেরত মান সত্য নাল হচ্ছে আউট প্যারামিটার পদ্ধতি চুক্তির একটি অংশ।
সেবাস্তিয়ান রেডল

এটি চুক্তির অংশ নয়। আশ্বাসপ্রাপ্ত একমাত্র বিষয় হ'ল আউট প্যারামিটারে কিছু বরাদ্দ করা হয়েছে
ইওয়ান

এটি এমন একটি আচরণ যা আমি কোনও TryParseপদ্ধতি থেকে প্রত্যাশা করি । যদি IPAddress.TryParseকখনও সত্য হয়ে যায় তবে এর আউট প্যারামিটারে নন-নাল বরাদ্দ না করা হলে আমি এটিকে একটি বাগ হিসাবে রিপোর্ট করব।
সেবাস্তিয়ান রেডল

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

"আপনার প্রত্যাশা বোধগম্য তবে এটি সংকলক দ্বারা প্রয়োগ করা হয়নি।" - আমি জানি, তবে আমার প্রশ্নটি হল যে আমার মনে যে চুক্তিটি আছে তা প্রকাশ করার জন্য কীভাবে আমার কোডটি সেরাভাবে লিখতে হয়, অন্য কোনও কোডের চুক্তি কী তা নয় not
সেবাস্তিয়ান রেডল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.