এই পদ্ধতি কি খাঁটি?


9

আমার কাছে নিম্নলিখিত এক্সটেনশন পদ্ধতি রয়েছে:

    public static IEnumerable<T> Apply<T>(
        [NotNull] this IEnumerable<T> source,
        [NotNull] Action<T> action)
        where T : class
    {
        source.CheckArgumentNull("source");
        action.CheckArgumentNull("action");
        return source.ApplyIterator(action);
    }

    private static IEnumerable<T> ApplyIterator<T>(this IEnumerable<T> source, Action<T> action)
        where T : class
    {
        foreach (var item in source)
        {
            action(item);
            yield return item;
        }
    }

এটি সিক্যুয়েন্সের প্রতিটি আইটেমকে ফেরত দেওয়ার আগে এটি প্রয়োগ করে।

আমি ভাবছিলাম যে আমাকে এই পদ্ধতির Pure(পুনঃভাগী টীকা থেকে) বৈশিষ্ট্যটি প্রয়োগ করা উচিত এবং আমি এর পক্ষে এবং এর বিপরীতে যুক্তিগুলি দেখতে পাচ্ছি।

পেশাদাররা:

  • কঠোরভাবে বলতে, এটা হল বিশুদ্ধ; কেবল একটি ক্রম এ এটি কল করা ক্রমটি পরিবর্তন করে না (এটি একটি নতুন অনুক্রম ফেরত দেয়) বা কোনও পর্যবেক্ষণযোগ্য রাষ্ট্র পরিবর্তন করে না
  • ফলাফলটি ব্যবহার না করে এটি কল করা স্পষ্টতই একটি ভুল, যেহেতু অনুক্রমটি গণনা করা না হলে এর কোনও প্রভাব নেই, তাই আমি চাই যদি আমি তা করে থাকি তবে রেশার্পার আমাকে সতর্ক করতে চান।

কনস:

  • যদিও Applyপদ্ধতি নিজেই বিশুদ্ধ হয়, enumerating ফলে ক্রম হবে পর্যবেক্ষণযোগ্য রাষ্ট্র পরিবর্তন করতে (যা পদ্ধতির বিন্দু)। উদাহরণস্বরূপ, items.Apply(i => i.Count++)প্রতিবার আইটেমটি গণিত হওয়ার মান পরিবর্তন করবে change সুতরাং বিশুদ্ধ বৈশিষ্ট্য প্রয়োগ করা সম্ভবত বিভ্রান্তিকর ...

আপনি কি মনে করেন? আমি গুণাবলী প্রয়োগ করা উচিত বা না?


উত্তর:


15

না এটি খাঁটি নয়, কারণ এর পার্শ্ব প্রতিক্রিয়া রয়েছে। কংক্রিটলি এটি actionপ্রতিটি আইটেমে কল করছে। এছাড়াও, এটি থ্রেডসেফ নয়।

খাঁটি ফাংশনগুলির প্রধান সম্পত্তি হ'ল এটিকে যে কোনও সংখ্যক বার বলা যেতে পারে এবং এটি একই মান ফেরত দেওয়া ছাড়া আর কিছুই করে না। যা আপনার ক্ষেত্রে নয়। এছাড়াও, খাঁটি হওয়ার অর্থ আপনি ইনপুট প্যারামিটারগুলি ছাড়া আর কিছু ব্যবহার করেন না। এর অর্থ এটি যে কোনও সময় যে কোনও থ্রেড থেকে কল করা যেতে পারে এবং কোনও অপ্রত্যাশিত আচরণের কারণ নয়। আবার, এটি আপনার ফাংশনের ক্ষেত্রে নয়।

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

এরিক লিপার্ট একটি ভাল পয়েন্ট উত্থাপন। আমি আমার পাল্টা-যুক্তির অংশ হিসাবে http://msdn.microsoft.com/en-us/library/dd264808(v=vs.110).aspx ব্যবহার করতে যাচ্ছি । বিশেষত লাইন

খাঁটি পদ্ধতিতে প্রবেশের পরে তৈরি করা বস্তুগুলিকে সংশোধন করার জন্য একটি খাঁটি পদ্ধতি অনুমোদিত is

যাক আমরা এই জাতীয় পদ্ধতি তৈরি করি:

int Count<T>(IEnumerable<T> e)
{
    var enumerator = e.GetEnumerator();
    int count = 0;
    while (enumerator.MoveNext()) count ++;
    return count;
}

প্রথমত, এটি ধরে নেওয়া যায় যে GetEnumeratorএটিও খাঁটি (আমি সত্যিই এর কোনও উত্স খুঁজে পাই না)। যদি এটি হয় তবে উপরের নিয়ম অনুসারে, আমরা এই পদ্ধতিটি [খাঁটি] দিয়ে টিকিয়ে দিতে পারি, কারণ এটি কেবলমাত্র দেহের মধ্যেই তৈরি হওয়া উদাহরণটিকে পরিবর্তন করে। এর পরে আমরা এই এবং এটি রচনা করতে পারি ApplyIterator, যার ফলস্বরূপ খাঁটি ফাংশন হওয়া উচিত, তাই না?

Count(ApplyIterator(source, action));

নং এই রচনা বিশুদ্ধ নয়, এমনকি যখন উভয় Countএবং ApplyIteratorবিশুদ্ধ হয়। তবে আমি এই যুক্তিটি ভুল ভিত্তিতে গড়ে তুলছি। আমি মনে করি যে পদ্ধতির মধ্যে যে দৃষ্টান্ত তৈরি হয়েছে তা বিশুদ্ধতা বিধি থেকে অব্যাহতিপ্রাপ্ত হয় ভুল হয় বা কমপক্ষে যথেষ্ট নির্দিষ্ট নয়।


1
+1 ফাংশন বিশুদ্ধতা কোনও উপকার বা বিপরীতে প্রশ্ন নয়। ফাংশন বিশুদ্ধতা ব্যবহার এবং সুরক্ষার জন্য একটি ইঙ্গিত। আশ্চর্যজনকভাবে যথেষ্ট পরিমাণে ওপি লাগিয়েছে where T : class, তবে যদি ওপিকে কেবল where T : strutএটি খাঁটি করা যায়।
আরটিস

4
আমি এই উত্তরের সাথে একমত নই। কল sequence.Apply(action)করার কোনও পার্শ্ব প্রতিক্রিয়া নেই; যদি এটি হয়, তবে এর যে পার্শ্ব প্রতিক্রিয়া রয়েছে তা উল্লেখ করুন। এখন, কল sequence.Apply(action).GetEnumerator().MoveNext()করার একটি পার্শ্ব প্রতিক্রিয়া রয়েছে, তবে আমরা এটি ইতিমধ্যে জানতাম; এটি গণককে পরিবর্তন করে! sequence.Apply(action)কলিংকে অশুদ্ধ বলে বিবেচনা করা উচিত MoveNext, তবে sequence.Where(predicate)খাঁটি হিসাবে বিবেচিত হবে? sequence.Where(predicate).GetEnumerator().MoveNext()অপরিষ্কার হিসাবে প্রতিটি বিট।
এরিক লিপার্ট

@ এরিকলিপার্ট আপনি একটি ভাল বিষয় উত্থাপন করেছেন। তবে, কেবলমাত্র getEnumerator কল করা কি যথেষ্ট হবে না? আমরা কি খাঁটি বিবেচনা করতে পারি?
ইউফোরিক

@ ইউফোরিক: GetEnumeratorপ্রাথমিক অবস্থায় একটি গণকের বরাদ্দ বাদ দিয়ে কলিং কী পর্যবেক্ষণযোগ্য পার্শ্ব প্রতিক্রিয়া তৈরি করে ?
এরিক লিপার্ট

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

18

আমি ইউফোরিক এবং রবার্ট হার্ভির উত্তর উভয়ের সাথেই একমত নই । অবশ্যই এটি একটি খাঁটি ফাংশন; সমস্যা হল যে

এটি সিক্যুয়েন্সের প্রতিটি আইটেমকে ফেরত দেওয়ার আগে এটি প্রয়োগ করে।

প্রথম "এর" অর্থ কী তা খুব অস্পষ্ট। যদি "এটি" এর অর্থ সেই ফাংশনগুলির মধ্যে একটি হয় তবে এটি সঠিক নয়; এই ফাংশনগুলির কোনওটিই তা করে না; MoveNextক্রম গণনাকারী যে নেই এবং এটি "আয়" প্রক্রিয়ার মাধ্যমে আইটেমটি Currentসম্পত্তি, এটা ফিরে দ্বারা নয়।

এই সিকোয়েন্সগুলি অলসভাবে গণনা করা হয় , আগ্রহের সাথে নয় তাই ক্রমটি ফিরে আসার আগে অবশ্যই ক্রিয়াটি প্রয়োগ করা হয় না Apply। ক্রমটি ক্রমটি ফিরে আসার পরে প্রয়োগ করা হয়, যদি MoveNextকোনও এনুমरेटरকে ডাকা হয়।

আপনি যেমন নোট করেছেন, এই ফাংশনগুলি একটি ক্রিয়া এবং একটি ক্রম নেয় এবং একটি অনুক্রম ফেরত দেয়; আউটপুট ইনপুট উপর নির্ভর করে, এবং কোন পার্শ্ব প্রতিক্রিয়া উত্পাদিত হয়, তাই এগুলি খাঁটি ফাংশন ..

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

এখন, আপনার প্রশ্নের হিসাবে, আপনি যদি এই বৈশিষ্ট্যটি প্রয়োগ করতে চান: আমি গুণটি প্রয়োগ করব না কারণ আমি এই পদ্ধতিটি প্রথম স্থানে লিখব না । যদি আমি কোনও ক্রমটিতে একটি ক্রিয়া প্রয়োগ করতে চাই তবে আমি লিখি

foreach(var item in sequence) action(item);

যা সুন্দরভাবে পরিষ্কার।


2
আমার ধারণা এই পদ্ধতিটি ForEachএক্সটেনশন পদ্ধতি হিসাবে একই ব্যাগে পড়ে যা ইচ্ছাকৃতভাবে লিনকের অংশ নয় কারণ এর লক্ষ্য পার্শ্ব প্রতিক্রিয়া তৈরি করা ...
টমাস লেভস্ক

1
@ থমাসলভেস্ক: আমার পরামর্শ হ'ল এটি কখনই না করা । একটি ক্যোয়ারিতে একটি প্রশ্নের উত্তর দেওয়া উচিত , কোনও ক্রমকে পরিবর্তন করা উচিত নয় ; এজন্য তাদের জিজ্ঞাসা বলা হয় । ক্রমটি জিজ্ঞাসিত হওয়ার সাথে সাথে মিউট করা অসাধারণ বিপজ্জনক । উদাহরণস্বরূপ বিবেচনা করুন যে যদি এই জাতীয় কোনও প্রশ্নের পরে Any()সময়ের সাথে একাধিক কল করা হয়; ক্রিয়াটি বারবার সম্পাদিত হবে তবে কেবল প্রথম আইটেমে! একটি ক্রম মানগুলির ক্রম হওয়া উচিত ; যদি আপনি একটি ক্রম চান ক্রিয়া তারপর করা IEnumerable<Action>
এরিক লিপার্ট

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

2
@ থমাসডিং: পদ্ধতিটি কল করে না action, সুতরাং এর বিশুদ্ধতা actionঅপ্রাসঙ্গিক। আমি জানি এটি দেখতে যেমন লাগে ঠিক তেমন action, তবে এই পদ্ধতিটি দুটি পদ্ধতির জন্য একটি সিনট্যাকটিক চিনি, একটি যা একটি এনুমরেটরকে ফেরত দেয়, এবং একটি যা MoveNextগণকের হয়। পূর্বেরটি পরিষ্কারভাবে খাঁটি এবং দ্বিতীয়টি পরিষ্কারভাবে নয়। এভাবে দেখুন: আপনি কি বলবেন যে IEnumerable ApplyIterator(whatever) { return new MyIterator(whatever); }এটি খাঁটি? কারণ এটি ফাংশন যা এটি সত্য।
এরিক লিপার্ট

1
@ থমাসডিং: আপনি কিছু মিস করছেন; এটি যে পুনরাবৃত্তি কাজ করে না। ApplyIteratorপদ্ধতি ফেরৎ অবিলম্বে । প্রত্যাবর্তিত অবজেক্টের গণকের ApplyIteratorপ্রথম কল না হওয়া পর্যন্ত এর শরীরে কোনও কোড চালিত হয় না MoveNext। এখন আপনি কি জানেন যে, আপনি এই ধাঁধা উত্তর অনুমান করতে পারেন: blogs.msdn.com/b/ericlippert/archive/2007/09/05/... উত্তর এখানে: blogs.msdn.com/b/ericlippert/archive /
2007/09/06

3

এটি খাঁটি ফাংশন নয়, তাই বিশুদ্ধ বৈশিষ্ট্য প্রয়োগ করা বিভ্রান্তিকর।

খাঁটি ফাংশনগুলি মূল সংগ্রহটি সংশোধন করে না এবং আপনি কোনও ক্রিয়াকলাপের কোনও প্রভাব ফেলছেন বা না পার করছেন তা বিবেচ্য নয়; এটি এখনও একটি অপবিত্র ফাংশন কারণ এর অভিপ্রায়টি পার্শ্ব প্রতিক্রিয়া সৃষ্টি করে।

আপনি যদি ফাংশনটি বিশুদ্ধ করতে চান তবে সংগ্রহটি একটি নতুন সংগ্রহের অনুলিপি করুন, অ্যাকশন নতুন সংগ্রহের পরিবর্তনের জন্য প্রয়োগ করুন এবং মূল সংগ্রহটি অপরিবর্তিত রেখে নতুন সংগ্রহটি ফিরিয়ে দিন।


ঠিক আছে, এটি মূল সংগ্রহটি কোনও পরিবর্তন করে না, যেহেতু এটি একই আইটেমগুলির সাথে কেবল একটি নতুন ক্রম ফিরিয়ে দেয়; এই কারণেই আমি এটি খাঁটি করার বিষয়ে বিবেচনা করছিলাম। আপনি ফলাফলটি গণনা করার সময় এটি আইটেমের অবস্থার পরিবর্তন করতে পারে।
থমাস লেভেস্ক

যদি itemকোনও রেফারেন্স টাইপ হয় তবে এটি itemপুনরুক্তি করে ফিরে আসার পরেও এটি মূল সংগ্রহটি পরিবর্তন করছে । স্ট্যাকওভারফ্লো.com
রবার্ট হার্ভে

1
এমনকি তিনি সংগ্রহটি গভীর-অনুলিপি করলেও এটি খাঁটি হবে না, যেমন এতে actionপাস করা আইটেমটি সংশোধন করা ছাড়া অন্য পার্শ্ব প্রতিক্রিয়াও থাকতে পারে।
ইদান আরে

@ ইডানআরি: সত্য, অ্যাকশনটিও খাঁটি হতে হবে।
রবার্ট হার্ভে

1
@ ইদানআরি: ()=>{}অ্যাকশনে রূপান্তরিত, এবং এটি একটি বিশুদ্ধ কাজ। এটির ফলাফলগুলি কেবলমাত্র তার ইনপুটগুলির উপর নির্ভর করে এবং এর কোনও পর্যবেক্ষণযোগ্য পার্শ্ব প্রতিক্রিয়া নেই।
এরিক লিপার্ট

0

আমার মতে, এটি কোনও ক্রিয়া গ্রহণ করে (এবং পিওরএকশন এর মতো কিছু নয়) এটি খাঁটি নয়।

এমনকি আমি এরিক লিপার্টের সাথেও একমত নই। তিনি এই লিখেছিলেন "() => {Action অ্যাকশনে রূপান্তরযোগ্য এবং এটি একটি খাঁটি ফাংশন It's এটির ফলাফলগুলি কেবল তার ইনপুটগুলির উপর নির্ভর করে এবং এর কোনও পর্যবেক্ষণযোগ্য পার্শ্ব প্রতিক্রিয়া নেই"।

ঠিক আছে, কল্পনা করুন যে প্রয়োগকারী ব্যবহারকারীর পরিবর্তে অ্যাকশন নামক একটি পদ্ধতিতে আবেদন করেছিলেন Apply

যদি অ্যাকশন খাঁটি হয় তবে অ্যাপ্লিকেশনটিও খাঁটি। যদি অ্যাকশন খাঁটি না হয় তবে অ্যাপ্লিকেশন বিশুদ্ধ হতে পারে না।

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

এটি অন্যভাবে ব্যাখ্যা করে, একটি খাঁটি পদ্ধতিতে সর্বদা একই ফলাফল দেওয়া উচিত একই রকম ইনপুটগুলি এবং পর্যবেক্ষণযোগ্য পরিবর্তনগুলি তৈরি করা উচিত নয়। প্রয়োগকারীকে একই উত্স এবং প্রতিনিধি দু'বার দেওয়া যেতে পারে তবে, যদি প্রতিনিধি একটি রেফারেন্স-ধরণের পরিবর্তন করে থাকে, পরবর্তী মৃত্যুদণ্ড কার্যকররূপে বিভিন্ন ফলাফল দেয়। উদাহরণ: প্রতিনিধি আইটেমের মতো কিছু করে on কনটেন্ট + = "পরিবর্তিত";

সুতরাং, "স্ট্রিং কনটেইনারগুলি" (টাইপ স্ট্রিংয়ের একটি সামগ্রীর সম্পত্তি সহ একটি বস্তু) এর উপরে অ্যাপ্লিকেশন ব্যবহার করে আমাদের এই মূল মানগুলি থাকতে পারে:

Test

Test2

প্রথম মৃত্যুদণ্ড কার্যকর হওয়ার পরে, তালিকাটিতে এটি থাকবে:

Test Changed

Test2 Changed

এবং এটি তৃতীয় বার:

Test Changed Changed

Test2 Changed Changed

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

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