मुझे यह प्रश्न बहुत अच्छा लगा और मुझे लगा कि मैं अंतर बताने के लिए कुछ इनपुट पर विचार करूंगा।
मुझे यह प्रश्न बहुत अच्छा लगा और मुझे लगा कि मैं अंतर बताने के लिए कुछ इनपुट पर विचार करूंगा।
जवाबों:
वे वास्तव में दो बहुत अलग चीजें हैं। "डेलिगेट" वास्तव में एक चर के लिए नाम है जो एक विधि या लैम्ब्डा का संदर्भ रखता है, और एक लैम्ब्डा एक स्थायी नाम के बिना एक विधि है।
कुछ सूक्ष्म अंतरों को छोड़कर लम्बदा अन्य विधियों की तरह हैं।
एक प्रतिनिधि इस तरह से परिभाषित किया गया है:
delegate Int32 BinaryIntOp(Int32 x, Int32 y);
एक प्रकार का बाइनरीइंटऑनप का एक चर या तो एक विधि या एक लैम्ब्डा उसे सौंपा जा सकता है, जब तक कि हस्ताक्षर एक ही है: दो Int32 तर्क और एक Int32 वापसी।
एक लंबोदर को इस तरह परिभाषित किया जा सकता है:
BinaryIntOp sumOfSquares = (a, b) => a*a + b*b;
ध्यान देने वाली एक और बात यह है कि यद्यपि जेनेरिक फ़ंक और एक्शन प्रकारों को अक्सर "लैम्ब्डा प्रकार" माना जाता है, वे किसी भी अन्य प्रतिनिधि के समान हैं। उनके बारे में अच्छी बात यह है कि वे अनिवार्य रूप से किसी भी प्रकार के प्रतिनिधि के लिए एक नाम परिभाषित करते हैं, जिसकी आपको आवश्यकता हो सकती है (4 मापदंडों तक, हालांकि आप निश्चित रूप से अपने खुद के अधिक जोड़ सकते हैं)। इसलिए यदि आप कई प्रकार के डेलिगेट प्रकारों का उपयोग कर रहे हैं, लेकिन एक से अधिक बार नहीं, तो आप फंक और एक्शन का उपयोग करके अपने कोड को प्रतिनिधि घोषणाओं के साथ अव्यवस्थित करने से बच सकते हैं।
यहां बताया गया है कि कैसे फनक और एक्शन "सिर्फ लंबोदर के लिए नहीं" हैं:
Int32 DiffOfSquares(Int32 x, Int32 y)
{
return x*x - y*y;
}
Func<Int32, Int32, Int32> funcPtr = DiffOfSquares;
यह जानने के लिए एक और उपयोगी बात यह है कि एक ही हस्ताक्षर के साथ प्रतिनिधि प्रकार (स्वयं तरीके नहीं) लेकिन अलग-अलग नामों को एक दूसरे के लिए निहित नहीं किया जाएगा। इसमें फंक और एक्शन प्रतिनिधि शामिल हैं। हालाँकि यदि हस्ताक्षर समान हैं, तो आप स्पष्ट रूप से उनके बीच कास्ट कर सकते हैं।
अतिरिक्त मील जा रहे हैं .... C # में फंक्शन लचीले हैं, जिसमें लैम्बडा और डेलिगेट्स का उपयोग किया गया है। लेकिन C # में "प्रथम श्रेणी के कार्य" नहीं हैं। आप उस फ़ंक्शन का प्रतिनिधित्व करने के लिए आवश्यक रूप से एक ऑब्जेक्ट बनाने के लिए एक प्रतिनिधि चर को सौंपे गए फ़ंक्शन के नाम का उपयोग कर सकते हैं। लेकिन यह वास्तव में एक कंपाइलर ट्रिक है। यदि आप एक फंक्शन का नाम डॉट (इसके बाद फंक्शन पर मेंबर एक्सेस करने की कोशिश करते हैं) लिखकर स्टेटमेंट शुरू करते हैं, तो आप पाएंगे कि वहां कोई भी सदस्य रेफरेंस के लिए नहीं है। ऑब्जेक्ट से भी नहीं। यह प्रोग्रामर को उपयोगी (और संभावित रूप से खतरनाक) चीजों को करने से रोकता है जैसे कि विस्तार विधियों को जोड़ना जो किसी भी फ़ंक्शन पर कहा जा सकता है। आप जो सबसे अच्छा कर सकते हैं, वह डेलिगेट वर्ग का ही विस्तार करता है, जो निश्चित रूप से उपयोगी भी है, लेकिन उतना नहीं।
अद्यतन: इसके अलावा Karg के उत्तर को गुमनाम प्रतिनिधियों बनाम विधियों और लैम्ब्डा के बीच के अंतर को स्पष्ट करते हुए देखें ।
अद्यतन 2: जेम्स हार्ट एक महत्वपूर्ण, हालांकि बहुत ही तकनीकी बनाता है, ध्यान दें कि लैम्ब्डा और डेलिगेट्स .NET इकाइयां नहीं हैं (यानी सीएलआर में एक प्रतिनिधि या लैम्ब्डा की कोई अवधारणा नहीं है), बल्कि वे फ्रेमवर्क और भाषा निर्माण हैं।
सवाल थोड़ा अस्पष्ट है, जो आपको मिल रहे उत्तरों में व्यापक असमानता की व्याख्या करता है।
आपने वास्तव में पूछा था कि .NET फ्रेमवर्क में लैम्ब्डा और डेलिगेट्स के बीच क्या अंतर है; यह कई चीजों में से एक हो सकता है। क्या आप पूछ रहे हो:
C # (या VB.NET) भाषा में लैम्ब्डा एक्सप्रेशन और अनाम डेलिगेट्स के बीच अंतर क्या है?
System.Linq.Expressions.LambdaExpression ऑब्जेक्ट और .NET 3.5 में System.Delegate ऑब्जेक्ट के बीच अंतर क्या है?
या उन चरम सीमाओं के बीच या आसपास कहीं कुछ?
कुछ लोग आपको इस सवाल का जवाब देने की कोशिश कर रहे हैं कि 'सी # लैंबडा एक्सप्रेशन और .NET.Delegate?' के बीच अंतर क्या है, जो पूरी तरह से समझ में नहीं आता है।
.NET फ्रेमवर्क अपने आप में अनाम डेलिगेट्स, लैम्ब्डा एक्सप्रेशन या क्लोज़र की अवधारणाओं को नहीं समझता है - ये सभी भाषा विनिर्देशों द्वारा परिभाषित की गई चीजें हैं। इस बारे में सोचें कि C # कंपाइलर क्लोजर स्टेट को होल्ड करने के लिए मेंबर वेरिएबल्स के साथ एक जेनरेट किए गए क्लास में एक मेथड का अनाउंसमेंट किस तरीके से करता है; .NET के लिए, प्रतिनिधि के बारे में कुछ भी अनाम नहीं है; यह लिखने वाले C # प्रोग्रामर के लिए बस गुमनाम है। यह एक प्रतिनिधि प्रकार को सौंपे गए लंबोदर अभिव्यक्ति के समान रूप से सच है।
.NET क्या समझता है एक प्रतिनिधि का विचार है - एक प्रकार जो एक विधि हस्ताक्षर का वर्णन करता है, जिसके उदाहरण विशिष्ट वस्तुओं पर विशिष्ट विधियों के लिए या तो बाध्य कॉल का प्रतिनिधित्व करते हैं, या किसी विशेष प्रकार पर किसी विशेष विधि के लिए अनबाउंड कॉल करते हैं, जिसके खिलाफ आह्वान किया जा सकता है उस प्रकार की कोई भी वस्तु, जहां उक्त विधि उक्त हस्ताक्षर का पालन करती है। इस प्रकार के सभी System.Delegate से विरासत में मिलते हैं।
.NET 3.5 भी System.Linq.Expressions नामस्थान का परिचय देता है, जिसमें कोड अभिव्यक्तियों का वर्णन करने के लिए कक्षाएं होती हैं - और जो विशेष प्रकार या ऑब्जेक्ट पर विधियों के लिए बाध्य या अनबाउंड कॉल का प्रतिनिधित्व भी कर सकती हैं। लैंबडाएक्सप्रेशन उदाहरणों को वास्तविक प्रतिनिधियों में संकलित किया जा सकता है (जिसमें अभिव्यक्ति की संरचना के आधार पर एक गतिशील विधि कोडेन्ग की जाती है, और एक प्रतिनिधि सूचक इसे लौटा दिया जाता है)।
C # में आप उक्त प्रकार के एक लैंबडा एक्सप्रेशन को निर्दिष्ट करके System.Expressions.Expression प्रकारों के उदाहरण उत्पन्न कर सकते हैं, जो रनटाइम पर अभिव्यक्ति के निर्माण के लिए उपयुक्त कोड का उत्पादन करेगा।
बेशक, अगर आप पूछ रहे थे कि लैम्ब्डा एक्सप्रेशन और अनाम तरीकों के बीच अंतर क्या है C # में, आखिरकार, तो यह सब बहुत अधिक प्रासंगिक है, और इस मामले में प्राथमिक अंतर संक्षिप्तता है, जो गुमनाम प्रतिनिधियों की ओर झुकता है जब आप डॉन ' मापदंडों के बारे में परवाह नहीं है और जब आप टाइप किए गए मानदंड और वापसी प्रकार चाहते हैं, तो एक मान वापस करने पर और लंबोदर की योजना न करें।
और लंबोदर भाव अभिव्यक्ति पीढ़ी का समर्थन करते हैं।
एक अंतर यह है कि एक गुमनाम प्रतिनिधि मापदंडों को छोड़ सकता है जबकि एक लंबोदर को सटीक हस्ताक्षर से मेल खाना चाहिए। दिया हुआ:
public delegate string TestDelegate(int i);
public void Test(TestDelegate d)
{}
आप इसे निम्नलिखित चार तरीकों से कह सकते हैं (ध्यान दें कि दूसरी पंक्ति में एक अनाम प्रतिनिधि है जिसमें कोई पैरामीटर नहीं है):
Test(delegate(int i) { return String.Empty; });
Test(delegate { return String.Empty; });
Test(i => String.Empty);
Test(D);
private string D(int i)
{
return String.Empty;
}
आप एक लैम्ब्डा अभिव्यक्ति में पास नहीं हो सकते हैं जिसमें कोई पैरामीटर नहीं है या एक ऐसी विधि है जिसमें कोई पैरामीटर नहीं है। इन्हें अनुमति नहीं है:
Test(() => String.Empty); //Not allowed, lambda must match signature
Test(D2); //Not allowed, method must match signature
private string D2()
{
return String.Empty;
}
एक प्रतिनिधि हमेशा मूल रूप से एक फ़ंक्शन पॉइंटर होता है। एक लैम्ब्डा एक प्रतिनिधि में बदल सकता है, लेकिन यह एक LINQ अभिव्यक्ति पेड़ में भी बदल सकता है। उदाहरण के लिए,
Func<int, int> f = x => x + 1;
Expression<Func<int, int>> exprTree = x => x + 1;
पहली पंक्ति एक प्रतिनिधि का उत्पादन करती है, जबकि दूसरी एक अभिव्यक्ति वृक्ष का निर्माण करती है।
लैम्ब्डा बस एक प्रतिनिधि पर सिंटैक्टिक चीनी होते हैं। कंपाइलर लैम्बदास को डेलीगेट्स में परिवर्तित करता है।
ये वही हैं, मुझे विश्वास है:
Delegate delegate = x => "hi!";
Delegate delegate = delegate(object x) { return "hi";};
Delegate
'प्रतिनिधि' से उदाहरण का नाम बदलते हैं , जो एक कीवर्ड है।
एक प्रतिनिधि एक समारोह हस्ताक्षर है; कुछ इस तरह
delegate string MyDelegate(int param1);
प्रतिनिधि एक निकाय को लागू नहीं करता है।
लैम्बडा एक फ़ंक्शन कॉल है जो प्रतिनिधि के हस्ताक्षर से मेल खाता है। उपरोक्त प्रतिनिधि के लिए, आप किसी भी का उपयोग कर सकते हैं;
(int i) => i.ToString();
(int i) => "ignored i";
(int i) => "Step " + i.ToString() + " of 10";
Delegate
प्रकार बुरी तरह से है, हालांकि नाम पर है; एक प्रकार की वस्तु बनाने से Delegate
वास्तव में एक चर बनता है जो कार्यों को पकड़ सकता है - वे लंबोदर, स्थिर तरीके या वर्ग विधियां हो सकते हैं।
एक प्रतिनिधि, फ़ंक्शन पॉइंटर्स की एक कतार है, एक प्रतिनिधि को आमंत्रित करने से कई तरीके हो सकते हैं। एक लंबोदर अनिवार्य रूप से एक अनाम विधि घोषणा है जिसे संकलक द्वारा अलग-अलग तरीके से व्याख्या की जा सकती है, यह इस संदर्भ पर निर्भर करता है कि इसे किस रूप में उपयोग किया जाता है।
आप एक प्रतिनिधि प्राप्त कर सकते हैं जो एक प्रतिनिधि के रूप में कास्टिंग करके एक विधि के रूप में लैम्ब्डा अभिव्यक्ति की ओर इशारा करता है, या यदि इसे एक पैरामीटर के रूप में पास कर रहा है जो एक विशिष्ट प्रतिनिधि प्रकार की अपेक्षा करता है तो कंपाइलर आपके लिए इसे डालेगा। LINQ स्टेटमेंट के अंदर इसका उपयोग करते हुए, लैम्ब्डा को कंपाइलर द्वारा केवल एक डेलीगेट के बजाय एक अभिव्यक्ति ट्री में अनुवाद किया जाएगा।
अंतर वास्तव में यह है कि एक लंबोदर एक तरीका है जो किसी अन्य अभिव्यक्ति के अंदर एक विधि को परिभाषित करता है, जबकि एक प्रतिनिधि एक वास्तविक वस्तु प्रकार है।
यह स्पष्ट है कि सवाल यह था कि "मेमने और अनाम प्रतिनिधियों के बीच अंतर क्या है ?" यहां सभी उत्तरों में से केवल एक व्यक्ति ने इसे सही पाया - मुख्य अंतर यह है कि लैम्ब्डा का उपयोग अभिव्यक्ति के पेड़ और साथ ही प्रतिनिधियों को बनाने के लिए किया जा सकता है।
आप MSDN पर अधिक पढ़ सकते हैं: http://msdn.microsoft.com/en-us/library/bb397687.aspx
प्रतिनिधि वास्तव में केवल कार्यों के लिए संरचनात्मक टाइपिंग हैं। आप नाममात्र टाइपिंग और एक अनाम वर्ग को लागू करने के साथ एक ही कार्य कर सकते हैं जो एक इंटरफ़ेस या अमूर्त वर्ग को लागू करता है, लेकिन यह बहुत सारे कोड होने पर समाप्त होता है जब केवल एक फ़ंक्शन की आवश्यकता होती है।
लैम्ब्डा 1930 के दशक में अलोंजो चर्च के लैम्ब्डा कैलकुलस के विचार से आता है। यह फ़ंक्शन बनाने का एक अनाम तरीका है। वे कार्यों की रचना के लिए विशेष रूप से उपयोगी हो जाते हैं
इसलिए जब कुछ लोग कह सकते हैं कि लैम्ब्डा प्रतिनिधियों के लिए सिंथेटिक चीनी है, तो मैं कहूंगा कि प्रतिनिधियों को सी # में लैम्ब्डा में लोगों को ढील देने के लिए एक पुल है।
कुछ बुनियादी यहाँ। "डेलिगेट" वास्तव में एक चर के लिए नाम है जो एक विधि या लैम्ब्डा का संदर्भ रखता है
यह एक अनाम विधि है -
(string testString) => { Console.WriteLine(testString); };
जैसा कि अनाम विधि में कोई नाम नहीं है, हमें एक प्रतिनिधि की आवश्यकता है जिसमें हम इन विधि या अभिव्यक्ति दोनों को असाइन कर सकते हैं। एक्स के लिए।
delegate void PrintTestString(string testString); // declare a delegate
PrintTestString print = (string testString) => { Console.WriteLine(testString); };
print();
लंबोदर अभिव्यक्ति के साथ भी। आमतौर पर हमें उन्हें इस्तेमाल करने के लिए प्रतिनिधि की आवश्यकता होती है
s => s.Age > someValue && s.Age < someValue // will return true/false
हम इस अभिव्यक्ति का उपयोग करने के लिए एक फंक प्रतिनिधि का उपयोग कर सकते हैं।
Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;
bool result = checkStudentAge ( Student Object);
लैम्ब्डा प्रतिनिधियों के सरलीकृत संस्करण हैं। उनके पास बंद प्रतिनिधियों के कुछ गुण हैं जैसे अनाम प्रतिनिधि, लेकिन यह भी आपको निहित टाइपिंग का उपयोग करने की अनुमति देता है। इस तरह एक लंबोदर:
something.Sort((x, y) => return x.CompareTo(y));
एक प्रतिनिधि के साथ आप क्या कर सकते हैं की तुलना में बहुत अधिक संक्षिप्त है:
something.Sort(sortMethod);
...
private int sortMethod(SomeType one, SomeType two)
{
one.CompareTo(two)
}
एक उदाहरण मैं अपने लंगड़ा ब्लॉग पर थोड़ी देर के लिए रखा। कहते हैं कि आप कार्यकर्ता थ्रेड से एक लेबल अपडेट करना चाहते थे। मुझे डेलमेटस, एनोन डेलिगेट्स और 2 प्रकार के लैम्ब्डा का उपयोग करके उस लेबल को 1 से 50 तक अपडेट करने के 4 उदाहरण मिले हैं।
private void button2_Click(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync();
}
private delegate void UpdateProgDelegate(int count);
private void UpdateText(int count)
{
if (this.lblTest.InvokeRequired)
{
UpdateProgDelegate updateCallBack = new UpdateProgDelegate(UpdateText);
this.Invoke(updateCallBack, new object[] { count });
}
else
{
lblTest.Text = count.ToString();
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
/* Old Skool delegate usage. See above for delegate and method definitions */
for (int i = 0; i < 50; i++)
{
UpdateText(i);
Thread.Sleep(50);
}
// Anonymous Method
for (int i = 0; i < 50; i++)
{
lblTest.Invoke((MethodInvoker)(delegate()
{
lblTest.Text = i.ToString();
}));
Thread.Sleep(50);
}
/* Lambda using the new Func delegate. This lets us take in an int and
* return a string. The last parameter is the return type. so
* So Func<int, string, double> would take in an int and a string
* and return a double. count is our int parameter.*/
Func<int, string> UpdateProgress = (count) => lblTest.Text = count.ToString();
for (int i = 0; i < 50; i++)
{
lblTest.Invoke(UpdateProgress, i);
Thread.Sleep(50);
}
/* Finally we have a totally inline Lambda using the Action delegate
* Action is more or less the same as Func but it returns void. We could
* use it with parameters if we wanted to like this:
* Action<string> UpdateProgress = (count) => lblT…*/
for (int i = 0; i < 50; i++)
{
lblTest.Invoke((Action)(() => lblTest.Text = i.ToString()));
Thread.Sleep(50);
}
}
मुझे लगता है कि आपके प्रश्न की चिंता c # है और .NET नहीं है, क्योंकि आपके प्रश्न की अस्पष्टता के कारण, .NET अकेले नहीं मिलता है - अर्थात, सी # के बिना - प्रतिनिधियों और लंबोदर अभिव्यक्तियों की समझ।
A ( सामान्य , तथाकथित सामान्य प्रतिनिधियों के विरोध में , cf बाद में) प्रतिनिधि को typedef
फ़ंक्शन सूचक प्रकार के c ++ के एक प्रकार के रूप में देखा जाना चाहिए , उदाहरण के लिए c ++ में:
R (*thefunctionpointer) ( T ) ;
typeedef का प्रकार thefunctionpointer
जो किसी प्रकार के ऑब्जेक्ट को लेने और किसी ऑब्जेक्ट के प्रकार T
को वापस करने वाले फ़ंक्शन का संकेत है R
। आप इसे इस तरह उपयोग करेंगे:
thefunctionpointer = &thefunction ;
R r = (*thefunctionpointer) ( t ) ; // where t is of type T
जहां thefunction
एक समारोह होगा T
और एक लौट रहा है R
।
सी # में आप के लिए जाना होगा
delegate R thedelegate( T t ) ; // and yes, here the identifier t is needed
और आप इसे इस तरह उपयोग करेंगे:
thedelegate thedel = thefunction ;
R r = thedel ( t ) ; // where t is of type T
जहां thefunction
एक समारोह में एक T
और एक वापस ले जाएगा R
। यह प्रतिनिधियों के लिए है, जिसे सामान्य प्रतिनिधि कहा जाता है।
अब, आपके पास c # में जेनेरिक डेलिगेट्स भी हैं, जो ऐसे डेलीगेट्स हैं, जो जेनेरिक हैं, यानी "templated" हैं इसलिए बोलने के लिए, जिससे c ++ एक्सप्रेशन का उपयोग किया जा सके। उन्हें इस तरह परिभाषित किया गया है:
public delegate TResult Func<in T, out TResult>(T arg);
और आप उन्हें इस तरह से उपयोग कर सकते हैं:
Func<double, double> thefunctor = thefunction2; // call it a functor because it is
// really as a functor that you should
// "see" it
double y = thefunctor(2.0);
जहां thefunction2
एक कार्य तर्क के रूप में होता है और वापस लौटता है double
।
अब कल्पना कीजिए कि इसके बजाय thefunction2
मैं एक "फ़ंक्शन" का उपयोग करना चाहूंगा, जो कि एक वक्तव्य द्वारा, अब के लिए कहीं भी परिभाषित नहीं है, और यह कि मैं बाद में कभी नहीं लिखूंगा। तब c # हमें इस फ़ंक्शन की अभिव्यक्ति का उपयोग करने की अनुमति देता है । अभिव्यक्ति से मेरा तात्पर्य "गणितीय" (या कार्यात्मक, कार्यक्रमों से चिपकना) है, इसकी अभिव्यक्ति, उदाहरण के लिए: double x
मैं एक सहयोगी से जुड़ूंगाdouble
x*x
। गणित में आप इसे "\ mapsto" लेटेक्स प्रतीक का उपयोग करके लिखते हैं । सी # में कार्यात्मक संकेतन उधार लिया गया है =>
:। उदाहरण के लिए :
Func<double, double> thefunctor = ( (double x) => x * x ); // outer brackets are not
// mandatory
(double x) => x * x
एक अभिव्यक्ति है । यह एक प्रकार नहीं है, जबकि प्रतिनिधि (सामान्य या नहीं) हैं।
नैतिकता? अंत में, क्या एक प्रतिनिधि (सम्मान। सामान्य प्रतिनिधि) है, अगर फ़ंक्शन पॉइंटर प्रकार नहीं है (सम्मान। लिपटे + स्मार्ट + जेनेरिक फ़ंक्शन सूचक प्रकार), हुह? कुछ और ! यह और वह देखें ।
खैर, वास्तव में ओवरसाइम्प्लीफाइड संस्करण यह है कि एक लैंबडा एक अनाम फ़ंक्शन के लिए सिर्फ शॉर्टहैंड है। एक प्रतिनिधि केवल अनाम कार्यों की तुलना में बहुत अधिक कर सकता है: घटनाओं, अतुल्यकालिक कॉल और कई विधि श्रृंखला जैसी चीजें।