সি # তে, কেন কোনও বেনামি পদ্ধতিতে ফলন বিবরণী থাকতে পারে না?


88

আমি ভেবেছিলাম এরকম কিছু করতে ভাল লাগবে (ল্যাম্বডা ফলন ফেরত দিয়ে):

public IList<T> Find<T>(Expression<Func<T, bool>> expression) where T : class, new()
{
    IList<T> list = GetList<T>();
    var fun = expression.Compile();

    var items = () => {
        foreach (var item in list)
            if (fun.Invoke(item))
                yield return item; // This is not allowed by C#
    }

    return items.ToList();
}

তবে, আমি জানতে পেরেছি যে আমি বেনাম পদ্ধতিতে ফলন ব্যবহার করতে পারি না। আমি ভাবছি কেন। ফলন ডক্স শুধু এটা মঞ্জুরিপ্রাপ্ত নয় বলে।

এটি অনুমোদিত না হওয়ায় আমি কেবল তালিকা তৈরি করেছি এবং এতে আইটেমগুলি যুক্ত করেছি added


এখন যেহেতু আমরা সি # 5.0 এ বেনামে asyncল্যাম্বডাস প্রবেশ করতে awaitপারি, তখনও তারা কেন yieldভিতরে বেনামে পুনরাবৃত্তি না করে তা জানতে আগ্রহী হব । কম বেশি, এটি একই স্টেট মেশিন জেনারেটর।
নাসেরটিও

উত্তর:


114

এরিক লিপার্ট সম্প্রতি কিছু ক্ষেত্রে কেন ফলন দেওয়া হচ্ছে না সে সম্পর্কে একাধিক ব্লগ পোস্ট লিখেছিলেন।

সম্পাদনা 2:

  • পর্ব 7 (এটি পরে পোস্ট করা হয়েছিল এবং বিশেষত এই প্রশ্নের সমাধান করে)

আপনি সম্ভবত উত্তর খুঁজে পাবেন ...


EDIT1: অভিজিৎ প্যাটেলের মন্তব্যে এরিকের উত্তরে পঞ্চম অংশের মন্তব্যে এটি ব্যাখ্যা করা হয়েছে:

প্রশ্ন:

এরিক,

বেনামে পদ্ধতিতে বা ল্যাম্বডা এক্সপ্রেশনের ভিতরে কেন "ফলন" দেওয়া যায় না সে সম্পর্কে আপনি কিছুটা অন্তর্দৃষ্টি দিতে পারেন?

উ:

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

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

এছাড়াও, পুনরাবৃত্তিকারী বেনামি পদ্ধতির বিপরীতে কখনও "নীড়" বাধা দেয় না। পুনরুক্তিকারী পুনরাবৃত্তি ধরে নিতে পারে যে সমস্ত পুনরুক্তিকারী ব্লকগুলি "শীর্ষ স্তর"।

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


4
আকর্ষণীয়, বিশেষত যেহেতু এখন স্থানীয় কার্যাদি রয়েছে।
মাফাই

4
আমি উত্তর দিচ্ছি যদি এই উত্তরটি পুরানো হয় তবে এটি কোনও স্থানীয় ফাংশনে ফলন ফেরত নেবে।
জোশুয়া

4
@ জোশুয়া কিন্তু একটি স্থানীয় ফাংশন বেনাম পদ্ধতির মতো নয় ... বেনাম পদ্ধতিতে ফলন ফেরতের অনুমতি এখনও নেই।
টমাস লেভেস্ক

21

এরিক লিপার্ট পুনরাবৃত্তকারী ব্লকগুলিতে সীমাবদ্ধতা (এবং সেই পছন্দগুলি প্রভাবিত করে নকশার সিদ্ধান্তগুলি) সম্পর্কে নিবন্ধগুলির একটি দুর্দান্ত সিরিজ লিখেছেন

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

ফলস্বরূপ তারা মিথস্ক্রিয়া থেকে নিষিদ্ধ।

হুডের নীচে পুনরাবৃত্তকারীদের কীভাবে ব্লক কাজ করে তা এখানে ভালভাবে মোকাবেলা করা হয় ।

অসম্পূর্ণতার সহজ উদাহরণ হিসাবে:

public IList<T> GreaterThan<T>(T t)
{
    IList<T> list = GetList<T>();
    var items = () => {
        foreach (var item in list)
            if (fun.Invoke(item))
                yield return item; // This is not allowed by C#
    }

    return items.ToList();
}

সংকলক একই সাথে এটিকে এমন কিছুতে রূপান্তর করতে চাইছে:

// inner class
private class Magic
{
    private T t;
    private IList<T> list;
    private Magic(List<T> list, T t) { this.list = list; this.t = t;}

    public IEnumerable<T> DoIt()
    {
        var items = () => {
            foreach (var item in list)
                if (fun.Invoke(item))
                    yield return item;
        }
    }
}

public IList<T> GreaterThan<T>(T t)
{
    var magic = new Magic(GetList<T>(), t)
    var items = magic.DoIt();
    return items.ToList();
}

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

তবে এটি হবে

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

আপনার উদাহরণে যেমন:

public IList<T> Find<T>(Expression<Func<T, bool>> expression) 
    where T : class, new()
{
    return FindInner(expression).ToList();
}

private IEnumerable<T> FindInner<T>(Expression<Func<T, bool>> expression) 
    where T : class, new()
{
    IList<T> list = GetList<T>();
    var fun = expression.Compile();
    foreach (var item in list)
        if (fun.Invoke(item))
            yield return item;
}

4
সংকলকটি যখন সমস্ত বন্ধ হয়ে যায়, সাধারণ পুনরাবৃত্তির রূপান্তরটি করতে পারে তার কোনও স্পষ্ট কারণ নেই। আপনি কি এমন কোনও ক্ষেত্রে জানেন যা আসলে কিছুটা অসুবিধা উপস্থাপন করবে? বিটিডব্লিউ, আপনার Magicক্লাস হওয়া উচিত Magic<T>
কিওয়ার্টি

4

দুর্ভাগ্যক্রমে আমি জানি না কেন তারা এটিকে অনুমতি দিলেন না, কারণ এটি কীভাবে কাজ করবে তা কল্পনা করা সম্পূর্ণভাবে সম্ভব।

তবে, বেনামে পদ্ধতিগুলি ইতিমধ্যে "কম্পাইলার ম্যাজিক" এর একটি টুকরো এই অর্থে যে পদ্ধতিটি স্থানীয় শ্রেণীর সাথে সম্পর্কিত কিনা তা নির্ভর করে বিদ্যমান শ্রেণীর কোনও পদ্ধতিতে বা এমনকি একটি সম্পূর্ণ নতুন শ্রেণিতেও বের করা হবে not

অতিরিক্তভাবে, পুনরাবৃত্তকারীগুলির ব্যবহারের পদ্ধতিগুলিও yieldসংকলক যাদু ব্যবহার করে প্রয়োগ করা হয়।

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

100% নির্ভুল প্রশ্নের জন্য আমি আপনাকে মাইক্রোসফ্ট কানেক্ট সাইটটি ব্যবহার করার এবং একটি প্রশ্নের প্রতিবেদন করার পরামর্শ দেব, আমি নিশ্চিত যে এর বিনিময়ে আপনি ব্যবহারযোগ্য কিছু পাবেন।


1

আমি এটি করব:

IList<T> list = GetList<T>();
var fun = expression.Compile();

return list.Where(item => fun.Invoke(item)).ToList();

অবশ্যই আপনার লিনক পদ্ধতির জন্য .NET 3.5 থেকে রেফারেন্স করা System.Core.dll দরকার। এবং অন্তর্ভুক্ত:

using System.Linq;

চিয়ার্স,

স্লাই


0

সম্ভবত এটি কেবল একটি বাক্য গঠন সীমাবদ্ধতা। ভিজ্যুয়াল বেসিক। নেট, যা সি # এর সাথে খুব মিলে যায়, লেখার জন্য বিশ্রী অবস্থায় এটি পুরোপুরি সম্ভব

Sub Main()
    Console.Write("x: ")
    Dim x = CInt(Console.ReadLine())
    For Each elem In Iterator Function()
                         Dim i = x
                         Do
                             Yield i
                             i += 1
                             x -= 1
                         Loop Until i = x + 20
                     End Function()
        Console.WriteLine($"{elem} to {x}")
    Next
    Console.ReadKey()
End Sub

প্রথম বন্ধনীগুলিও নোট করুন ' here; ল্যাম্বদা ফাংশন Iterator Function... একটি End Function ফেরত দেয়IEnumerable(Of Integer) তবে এটি নিজেই কোনও বস্তু নয়। এটি অবশ্যই পেতে হবে object বস্তুটি পেতে।

[1] দ্বারা রূপান্তরিত কোডটি সি # 7.3 (CS0149) এ ত্রুটি উত্থাপন করে:

static void Main()
{
    Console.Write("x: ");
    var x = System.Convert.ToInt32(Console.ReadLine());
    // ERROR: CS0149 - Method name expected 
    foreach (var elem in () =>
    {
        var i = x;
        do
        {
            yield return i;
            i += 1;
            x -= 1;
        }
        while (!i == x + 20);
    }())
        Console.WriteLine($"{elem} to {x}");
    Console.ReadKey();
}

অন্য উত্তরগুলিতে প্রদত্ত কারণের সাথে আমি দৃ strongly়ভাবে একমত নই যে সংকলকটির পক্ষে এটি পরিচালনা করা কঠিন। Iterator Function()আপনি VB.NET উদাহরণে দেখতে বিশেষভাবে ল্যামডা iterators জন্য তৈরি করা হয়।

ভিবিতে, Iteratorকীওয়ার্ড রয়েছে; এটির কোনও সি # সমকক্ষ নেই। আইএমএইচও, এটির কোনও কারণ নেই যা এটি সি # এর বৈশিষ্ট্য নয়।

সুতরাং আপনি যদি সত্যই, বেনামে পুনরাবৃত্তিকারী ফাংশনগুলি চান, তবে বর্তমানে ভিজুয়াল বেসিকটি ব্যবহার করুন বা (আমি এটি পরীক্ষা করে দেখিনি) F #, যেমন @ থমাস লেভেস্কির উত্তরে পার্ট # 7 এর মন্তব্যে বলা হয়েছে (F # এর জন্য Ctrl + F করুন)।

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