একটি পুনরাবৃত্তকারী একটি অ-ধ্বংসাত্মক অন্তর্ভুক্ত চুক্তি আছে?


11

ধরা যাক আমি স্ট্যাক বা একটি সারিগুলির মতো একটি কাস্টম ডেটা কাঠামো ডিজাইন করছি (উদাহরণস্বরূপ - এমন কিছু অন্যরকম আদেশযুক্ত সংগ্রহ হতে পারে যার যৌক্তিক সমীকরণ pushএবং popপদ্ধতিগুলি রয়েছে - যেমন ধ্বংসাত্মক অ্যাকসেসর পদ্ধতিগুলি)।

আপনি যদি IEnumerable<T>প্রতিটি পুনরাবৃত্তির উপরে উত্থাপিত এই সংগ্রহের উপরে যদি কোনও পুনরাবৃত্তকারী (বিশেষত নেট মধ্যে ) প্রয়োগ করে থাকেন, তবে তা কি ভঙ্গুর IEnumerable<T>নির্দেশিত চুক্তিটি ভঙ্গ করবে ?

না IEnumerable<T>এই উহ্য চুক্তি আছে?

উদাহরণ:

public IEnumerator<T> GetEnumerator()
{
    if (this.list.Count > 0)
        yield return this.Pop();
    else
        yield break;
}

উত্তর:


12

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

static void UpdateStatus<T>(IEnumerable<T> collection) where T : IBusinessObject
{
    foreach (var item in collection)
    {
        item.Status = BusinessObjectStatus.Foo;
    }
}

আর একজন বিকাশকারী যিনি আমার বাস্তবায়ন বা আপনার বাস্তবায়ন সম্পর্কে কিছুই জানেন না নির্দোষভাবে উভয়কেই ব্যবহার করার সিদ্ধান্ত নেন। সম্ভবত তারা ফলাফল দেখে অবাক হবেন:

//developer uses your type without thinking about the details
var collection = GetYourEnumerableType<SomeBusinessObject>();

//developer uses my function without thinking about the details
UpdateStatus<SomeBusinessObject>(collection);

এমনকি বিকাশকারী ধ্বংসাত্মক গণনার বিষয়ে অবগত থাকলেও, সংগ্রহটি একটি ব্ল্যাক-বাক্স ফাংশনে হস্তান্তর করার সময় তারা পুনরুক্তিগুলি সম্পর্কে চিন্তা করতে পারে না। এর লেখক হিসাবে UpdateStatus, আমি সম্ভবত আমার নকশায় ধ্বংসাত্মক গণনা বিবেচনা করব না।

তবে এটি কেবল একটি নিহিত চুক্তি। নেট সংগ্রহগুলি সহ Stack<T>, তাদের সাথে একটি স্পষ্ট চুক্তি প্রয়োগ করে InvalidOperationException- "গণকটি তাত্ক্ষণিকভাবে শনাক্ত করার পরে সংগ্রহটি সংশোধন করা হয়েছিল"। আপনি তর্ক করতে পারেন যে কোনও প্রকৃত পেশাদারের নিজস্ব নয় এমন কোনও কোডের প্রতি সতর্ক মনোভাব রয়েছে। একটি ধ্বংসাত্মক গণকের বিস্ময়টি সর্বনিম্ন পরীক্ষার মাধ্যমে আবিষ্কার করা হবে।


1
+1 - 'সবচেয়ে স্বল্প বিস্ময়ের মূলনীতি'র জন্য আমি জনগণের কাছে এটি উদ্ধৃত করতে যাচ্ছি।

+1 মূলত এটি আমিও ভেবেছিলাম, ধ্বংসাত্মক হওয়ার কারণে লিনকিউ আইএনওমারেবল এক্সটেনশনের প্রত্যাশিত আচরণটিও ভেঙে যেতে পারে। সাধারণ / ধ্বংসাত্মক ক্রিয়াকলাপ না করেই এই ধরণের অর্ডার করা সংগ্রহটি নিয়ে পুনরাবৃত্তি হওয়া কেবল বিশ্রী বোধ করে।
স্টিভেন এভার্স

1

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

এই বাস্তবায়ন থেকে একটি আইনিউমারেটর তৈরি করা উত্তরোত্তর। এবং আমি আপনাকে একটি ফাংশনাল কুইউ বাস্তবায়ন করতে বলি যা একটি পারফরম্যান্ট ফাংশনাল স্ট্যাক (স্ট্যাক পুশ / পপ উভয়ই লেজটিতে কাজ করে, একটি সারিতে এনেকু লেজের উপর কাজ করে, ডেকিউ মাথায় কাজ করে) কার্যকর করার চেয়ে অনেক বেশি কঠিন is

আমার বক্তব্যটি ... আপনার নিজের পয়েন্টার মেকানিজম (স্ট্যাকনোড <টি>) প্রয়োগ করে এবং এনুমরেটরটিতে ক্রিয়ামূলক শব্দার্থক শব্দ ব্যবহার করে একটি ননডেস্ট্রাক্টিভ স্ট্যাক এনুমুলেটর তৈরি করা তুচ্ছ।

public class Stack<T> implements IEnumerator<T>
{
  private class StackNode<T>
  {
    private readonly T _data;
    private readonly StackNode<T> _next;
    public StackNode(T data, StackNode<T> next)
    {
       _data=data;
       _next=next;
    }
    public <T> Data{get {return _data;}}
    public StackNode<T> Next{get {return _Next;}}
  }

  private StackNode<T> _head;

  public void Push(T item)
  {
    _head =new StackNode<T>(item,_head);
  }

  public T Pop()
  {
    //Add in handling for a null head (i.e. fresh stack)
    var temp=_head.Data;
    _head=_head.Next;
    return temp;
  }

  ///Here's the fun part
  public IEnumerator<T> GetEnumerator()
  {
    //make a copy.
    var current=_head;
    while(current!=null)
    {
       yield return current.Data;
       current=_head.Next;
    }
  }    
}

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

এবং আমার বন্ধুটি হ'ল আপনি কীভাবে একটি স্ট্যাকের অ-ধ্বংসাত্মক গণনা করেন।


+1: আমার অ-ধ্বংসাত্মক স্ট্যাক এবং ক্যু এনুমারেটর একইভাবে প্রয়োগ করা হয়েছে। আমি কাস্টম তুলনাকারীদের সাথে পিকিউ / হিপসের লাইন ধরে আরও ভাবছিলাম।
স্টিভেন এভার্স

1
আমি একই পন্থাটি ব্যবহার করতে চাই ... এটির আগে আমি একটি কার্যকরী পিকিউ প্রয়োগ করতে পারি না ... যদিও এই নিবন্ধটির মতো মনে হচ্ছে আদেশযুক্ত ক্রমগুলি একটি অ-রৈখিক সমীকরণ হিসাবে ব্যবহার করার পরামর্শ দেয়
মাইকেল ব্রাউন

0

জিনিসগুলিকে "সরল" রাখার প্রয়াসে .NET এর কাছে কেবল একটি জেনেরিক / নন-জেনেরিক ইন্টারফেস রয়েছে যা কল করে GetEnumerator()এবং তারপরে প্রাপ্ত অবজেক্টটি ব্যবহার করে MoveNextএবং তার মাধ্যমে Currentপ্রাপ্ত বস্তুর উপর অন্তত চার ধরণের অবজেক্ট থাকা সত্ত্বেও গণনা করা হয় যা কেবলমাত্র সেই পদ্ধতিগুলিকে সমর্থন করবে:

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

উচ্চতর সংখ্যার সংজ্ঞাগুলির মধ্যে একটিকে সন্তুষ্ট করে এমন যে কোনও উদাহরণটি নীচের সমস্তগুলিও সন্তুষ্ট করবে, তবে নীচের একটিকে যদি দেওয়া হয় তবে উচ্চতর সংজ্ঞাগুলির মধ্যে একটির সন্তুষ্টিজনক কোনও সামগ্রীর জন্য কোডটি ভেঙে যেতে পারে।

দেখা যাচ্ছে যে মাইক্রোসফ্ট সিদ্ধান্ত নিয়েছে যে যে ক্লাসগুলি প্রয়োগ করে IEnumerable<T>তাদের দ্বিতীয় সংজ্ঞাটি পূরণ করা উচিত, তবে এর চেয়ে বেশি কিছু সন্তুষ্ট করার কোনও বাধ্যবাধকতা নেই। যুক্তিযুক্তভাবে, এমন কোনও কারণ নেই যা কেবলমাত্র প্রথম সংজ্ঞাটি পূরণ করতে পারে তার IEnumerable<T>পরিবর্তে প্রয়োগ করা উচিত IEnumerator<T>; যদি foreachলুপগুলি গ্রহণ IEnumerator<T>করতে পারে তবে কেবলমাত্র পরবর্তী ইন্টারফেসটি কার্যকর করার জন্য এটি একবারে গণনা করা যেতে পারে। দুর্ভাগ্যক্রমে, যে পদ্ধতিগুলি কেবল প্রয়োগ করে IEnumerator<T>সেগুলি পদ্ধতিযুক্ত ধরণের তুলনায় সি # এবং ভিবি.এনইটি তে কম সুবিধাজনক GetEnumerator

যাই হোক না কেন, যদিও এটি কার্যকর হবে যদি বিভিন্ন গ্যারান্টি দিতে পারে এমন জিনিসগুলির জন্য বিভিন্ন ধরণের গণ্যমান্য প্রকারগুলি থাকে, এবং / অথবা এমন কোনও উদাহরণ জিজ্ঞাসা করার একটি স্ট্যান্ডার্ড পদ্ধতি IEnumerable<T>যা এটি কী গ্যারান্টি দেয় তা কার্যকর করে , এমন কোন ধরণের এখনও বিদ্যমান নেই।


0

আমি মনে করি এটি লিসকভের প্রতিস্থাপন নীতি লঙ্ঘন হবে যা বলেছে যে,

কোনও প্রোগ্রামের অবজেক্টগুলিকে সেই প্রোগ্রামের যথার্থতা পরিবর্তন না করে তাদের উপ-টাইপের উদাহরণ সহ প্রতিস্থাপনযোগ্য হওয়া উচিত।

আমার যদি নীচের মতো একটি পদ্ধতি থাকে যা আমার প্রোগ্রামে একাধিকবার বলা হয়,

PrintCollection<T>(IEnumerable<T> collection)
{
    foreach (T item in collection)
    {
        Console.WriteLine(item);
    }
}

প্রোগ্রামের যথার্থতা পরিবর্তন না করেই আমার যে কোনও আইনিউমারেবল অদলবদল করতে সক্ষম হওয়া উচিত, তবে ধ্বংসাত্মক সারিটি ব্যবহার করা প্রোগ্রামের আচরণকে ব্যাপকভাবে পরিবর্তিত করতে পারে।

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