একটি মাত্র প্যারামিটার থাকলেও ল্যাম্বডা সিনট্যাক্স পছন্দ করার কোনও কারণ আছে কি?


14
List.ForEach(Console.WriteLine);

List.ForEach(s => Console.WriteLine(s));

আমার কাছে, পার্থক্যটি সম্পূর্ণরূপে প্রসাধনী, তবে কোনও সূক্ষ্ম কারণেই কেন একজনকে অপরটির চেয়ে বেশি পছন্দ করা যেতে পারে?


আমার অভিজ্ঞতায় যখনই দ্বিতীয় সংস্করণটি পছন্দনীয় মনে হচ্ছিল এটি সাধারণত প্রশ্নটির মধ্যে থাকা পদ্ধতিটির নামকরণের কারণ ছিল।
রোমান রিনার 13

উত্তর:


23

আইএলএসপিএসের মাধ্যমে সংকলিত কোডটির দিকে তাকানো, দুটি রেফারেন্সের মধ্যে আসলে একটি পার্থক্য রয়েছে। এর মতো সরল কর্মসূচির জন্য:

namespace ScratchLambda
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    internal class Program
    {
        private static void Main(string[] args)
        {
            var list = Enumerable.Range(1, 10).ToList();
            ExplicitLambda(list);
            ImplicitLambda(list);
        }

        private static void ImplicitLambda(List<int> list)
        {
            list.ForEach(Console.WriteLine);
        }

        private static void ExplicitLambda(List<int> list)
        {
            list.ForEach(s => Console.WriteLine(s));
        }
    }
}

আইএলএসপিএস এটি এটিকে বিযুক্ত করে:

using System;
using System.Collections.Generic;
using System.Linq;
namespace ScratchLambda
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            List<int> list = Enumerable.Range(1, 10).ToList<int>();
            Program.ExplicitLambda(list);
            Program.ImplicitLambda(list);
        }
        private static void ImplicitLambda(List<int> list)
        {
            list.ForEach(new Action<int>(Console.WriteLine));
        }
        private static void ExplicitLambda(List<int> list)
        {
            list.ForEach(delegate(int s)
            {
                Console.WriteLine(s);
            }
            );
        }
    }
}

আপনি যদি উভয়ের জন্য আইএল কল স্ট্যাকের দিকে তাকান, সুস্পষ্ট বাস্তবায়নের আরও অনেক কল রয়েছে (এবং একটি উত্পন্ন পদ্ধতি তৈরি করে):

.method private hidebysig static 
    void ExplicitLambda (
        class [mscorlib]System.Collections.Generic.List`1<int32> list
    ) cil managed 
{
    // Method begins at RVA 0x2093
    // Code size 36 (0x24)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: ldsfld class [mscorlib]System.Action`1<int32> ScratchLambda.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
    IL_0006: brtrue.s IL_0019

    IL_0008: ldnull
    IL_0009: ldftn void ScratchLambda.Program::'<ExplicitLambda>b__0'(int32)
    IL_000f: newobj instance void class [mscorlib]System.Action`1<int32>::.ctor(object, native int)
    IL_0014: stsfld class [mscorlib]System.Action`1<int32> ScratchLambda.Program::'CS$<>9__CachedAnonymousMethodDelegate1'

    IL_0019: ldsfld class [mscorlib]System.Action`1<int32> ScratchLambda.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
    IL_001e: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::ForEach(class [mscorlib]System.Action`1<!0>)
    IL_0023: ret
} // end of method Program::ExplicitLambda


.method private hidebysig static 
    void '<ExplicitLambda>b__0' (
        int32 s
    ) cil managed 
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
        01 00 00 00
    )
    // Method begins at RVA 0x208b
    // Code size 7 (0x7)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call void [mscorlib]System.Console::WriteLine(int32)
    IL_0006: ret
} // end of method Program::'<ExplicitLambda>b__0'

অন্তর্নিহিত বাস্তবায়ন আরও সংক্ষিপ্ত:

.method private hidebysig static 
    void ImplicitLambda (
        class [mscorlib]System.Collections.Generic.List`1<int32> list
    ) cil managed 
{
    // Method begins at RVA 0x2077
    // Code size 19 (0x13)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: ldnull
    IL_0002: ldftn void [mscorlib]System.Console::WriteLine(int32)
    IL_0008: newobj instance void class [mscorlib]System.Action`1<int32>::.ctor(object, native int)
    IL_000d: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::ForEach(class [mscorlib]System.Action`1<!0>)
    IL_0012: ret
} // end of method Program::ImplicitLambda

দ্রষ্টব্য যে এটি একটি দ্রুত স্ক্র্যাচ প্রোগ্রাম থেকে কোডের রিলিজ বিল্ড, সুতরাং আরও অনুকূলিতকরণের জন্য জায়গা থাকতে পারে। তবে এটি ভিজ্যুয়াল স্টুডিওর ডিফল্ট আউটপুট।
এজেন্ট_9191

2
+1 কারণ লাম্বদা সিনট্যাক্সটি অজ্ঞাতনামা ফাংশনে <কা> কোনও কারণ ছাড়াই কাঁচা পদ্ধতি কলটি মোড়ানো হয় </ i>। এটি সম্পূর্ণরূপে অর্থহীন, সুতরাং এটি উপলভ্য হওয়ার পরে আপনার কাঁচা পদ্ধতি গোষ্ঠীটি Func <> পরামিতি হিসাবে ব্যবহার করা উচিত।
এড জেমস

বাহ, আপনি সবুজ রঙের টিকটি পান, গবেষণার জন্য!
বেনজল

2

আমি সাধারণভাবে ল্যাম্বডা সিনট্যাক্স পছন্দ করি । আপনি যখন এটি দেখেন, তারপরে এটি আপনাকে কী ধরণের তা বলে দেয়। আপনি যখন দেখবেন Console.WriteLine, আপনাকে আইডিই জিজ্ঞাসা করতে হবে এটি কী ধরণের। অবশ্যই, এই তুচ্ছ উদাহরণে এটি সুস্পষ্ট, তবে সাধারণ ক্ষেত্রে এটি এতটা নাও হতে পারে।


আমি যেখানে প্রয়োজন সেখানে সামঞ্জস্যের জন্য ল্যাবমডা সিনট্যাক্সটি পছন্দ করব।
22:25

4
আমি কোনও সি # ব্যক্তির মধ্যে নই, তবে আমি যে ভাষাগুলিতে ল্যাম্বডাস (জাভাস্ক্রিপ্ট, স্কিম এবং হাস্কেল) ব্যবহার করেছি তারা সম্ভবত বিপরীত পরামর্শ দেবে। আমি মনে করি যে ভাষা-নির্ভর কতটা ভাল শৈলী তা দেখায়।
তিখন জেলভিস

এটি আপনাকে কীভাবে প্রকারটি বলে? অবশ্যই আপনি ল্যাম্বডাস প্যারামিটারের ধরণ সম্পর্কে স্পষ্ট করে বলতে পারেন তবে এটি করা সাধারণ থেকে দূরে এবং এই পরিস্থিতিতে এটি করা যায় না
জে কে।

1

আপনি যে দুটি উদাহরণ দিয়েছিলেন সেগুলির সাথে সেগুলি আলাদা হয় যখন আপনি বলবেন

List.ForEach(Console.WriteLine) 

আপনি লিখিতলাইন পদ্ধতিটি ব্যবহার করার জন্য ফোরিচ লুপটি আসলে বলছেন

List.ForEach(s => Console.WriteLine(s));

প্রকৃতপক্ষে এমন কোনও পদ্ধতির সংজ্ঞা দিচ্ছে যা পূর্বাভাস কল করবে এবং তারপরে আপনি সেখানে কী পরিচালনা করবেন তা বলছেন।

সুতরাং সহজ একটি লাইনারের জন্য যদি আপনার পদ্ধতিটি আপনি কল করতে যাচ্ছেন সেই পদ্ধতিটির মতো একই স্বাক্ষর বহন করে যা ইতিমধ্যে বলা হয়ে থাকে আমি ল্যাম্বডাকে সংজ্ঞায়িত না করা পছন্দ করি, আমি মনে করি এটি আরও কিছুটা পাঠযোগ্য।

অসম্পূর্ণ ল্যাম্বডাস সহ পদ্ধতিগুলি অবশ্যই খুব বেশি জটিল হওয়ার কথা নয় ধরে নিয়ে যাওয়া ভাল উপায় way


1

প্রথম লাইনটি পছন্দ করার পক্ষে খুব দৃ strong় কারণ রয়েছে।

প্রতিটি প্রতিনিধি একটি Targetসম্পত্তি আছে, যা প্রতিনিধিদের দৃষ্টান্ত সুযোগের বাইরে চলে যাওয়ার পরেও উদাহরণ পদ্ধতিগুলি উল্লেখ করার অনুমতি দেয়।

public class A {
    public int Data;
    public void WriteData() {
        Console.WriteLine(this.Data);
    }
}

var a1 = new A() {Data=4};
Action action = a1.WriteData;
a1 = null;

আমরা কল করতে পারি না a1.WriteData();কারণ a1নাল। যাইহোক, আমরা actionকোনও সমস্যা ছাড়াই প্রতিনিধিকে ডাকতে পারি , এবং এটি মুদ্রণ করবে 4, কারণ actionপদ্ধতিটি বলা উচিত সেই উদাহরণটির একটি উল্লেখ রয়েছে।

উদাহরণস্বরূপ যখন বেনামী পদ্ধতিগুলি প্রতিনিধি হিসাবে পাস করা হয়, তখন প্রতিনিধিটি ধারণকৃত শ্রেণীর একটি রেফারেন্স রাখবে, যদিও তা স্পষ্ট নয়:

public class Container {
    private List<int> data = new List<int>() {1,2,3,4,5};
    public void PrintItems() {
        //There is an implicit reference to an instance of Container here
        data.ForEach(s => Console.WriteLine(s));
    }
}

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

অন্যদিকে স্থিতিশীল পদ্ধতিগুলির উল্লেখের উদাহরণ নেই। নীচের উদাহরণের সাথে অন্তর্নিহিত রেফারেন্স থাকবে না Container:

public class Container {
    private List<int> data = new List<int>() {1,2,3,4,5};
    public void PrintItems() {
        //Since Console.WriteLine is a static method, there is no implicit reference
        data.ForEach(Console.WriteLine);
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.