List.ForEach(Console.WriteLine);
List.ForEach(s => Console.WriteLine(s));
আমার কাছে, পার্থক্যটি সম্পূর্ণরূপে প্রসাধনী, তবে কোনও সূক্ষ্ম কারণেই কেন একজনকে অপরটির চেয়ে বেশি পছন্দ করা যেতে পারে?
List.ForEach(Console.WriteLine);
List.ForEach(s => Console.WriteLine(s));
আমার কাছে, পার্থক্যটি সম্পূর্ণরূপে প্রসাধনী, তবে কোনও সূক্ষ্ম কারণেই কেন একজনকে অপরটির চেয়ে বেশি পছন্দ করা যেতে পারে?
উত্তর:
আইএলএসপিএসের মাধ্যমে সংকলিত কোডটির দিকে তাকানো, দুটি রেফারেন্সের মধ্যে আসলে একটি পার্থক্য রয়েছে। এর মতো সরল কর্মসূচির জন্য:
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
আমি সাধারণভাবে ল্যাম্বডা সিনট্যাক্স পছন্দ করি । আপনি যখন এটি দেখেন, তারপরে এটি আপনাকে কী ধরণের তা বলে দেয়। আপনি যখন দেখবেন Console.WriteLine
, আপনাকে আইডিই জিজ্ঞাসা করতে হবে এটি কী ধরণের। অবশ্যই, এই তুচ্ছ উদাহরণে এটি সুস্পষ্ট, তবে সাধারণ ক্ষেত্রে এটি এতটা নাও হতে পারে।
আপনি যে দুটি উদাহরণ দিয়েছিলেন সেগুলির সাথে সেগুলি আলাদা হয় যখন আপনি বলবেন
List.ForEach(Console.WriteLine)
আপনি লিখিতলাইন পদ্ধতিটি ব্যবহার করার জন্য ফোরিচ লুপটি আসলে বলছেন
List.ForEach(s => Console.WriteLine(s));
প্রকৃতপক্ষে এমন কোনও পদ্ধতির সংজ্ঞা দিচ্ছে যা পূর্বাভাস কল করবে এবং তারপরে আপনি সেখানে কী পরিচালনা করবেন তা বলছেন।
সুতরাং সহজ একটি লাইনারের জন্য যদি আপনার পদ্ধতিটি আপনি কল করতে যাচ্ছেন সেই পদ্ধতিটির মতো একই স্বাক্ষর বহন করে যা ইতিমধ্যে বলা হয়ে থাকে আমি ল্যাম্বডাকে সংজ্ঞায়িত না করা পছন্দ করি, আমি মনে করি এটি আরও কিছুটা পাঠযোগ্য।
অসম্পূর্ণ ল্যাম্বডাস সহ পদ্ধতিগুলি অবশ্যই খুব বেশি জটিল হওয়ার কথা নয় ধরে নিয়ে যাওয়া ভাল উপায় way
প্রথম লাইনটি পছন্দ করার পক্ষে খুব দৃ 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);
}
}