ओलिवियर का जवाब मूल रूप से सही है लेकिन यह कुछ अतिरिक्त स्पष्टीकरण का उपयोग कर सकता है।
स्थिर कारखाने विधि के लिए रिटर्न प्रकार को प्रतिबिंबित करने से कंक्रीट प्रकार क्यों मिलता है, जबकि कन्स्ट्रक्टर इनलाइन को इंटरफ़ेस देता है? मैं होना दोनों के लिए उन्हें उम्मीद होती है एक ही
आपका प्रोग्राम वर्ग निम्नलिखित वर्ग के बराबर है:
class Program
{
static void Test(ThingCreator creator)
{
Console.WriteLine(creator.Method.ReturnType);
}
static IThing Anon1()
{
return new Foo();
}
static IThing Anon2()
{
return new Bar();
}
static void Main()
{
Test(new ThingCreator(Foo.Create));
Test(new ThingCreator(Bar.Create));
Test(new ThingCreator(Program.Anon1));
Test(new ThingCreator(Program.Anon2));
}
}
और अब यह स्पष्ट किया जाना चाहिए क्यों कार्यक्रम प्रिंट यह क्या करता है।
कहानी यहाँ का नैतिक है कि जब हम lambdas के लिए छिपा विधि उत्पन्न करते हैं, उन छुपा तरीकों लौट जो कुछ प्रतिनिधि की आवश्यकता थी, और नहीं जो कुछ भी लैम्ब्डा रिटर्न है।
वह क्यों है?
एक और अधिक सार्थक उदाहरण है कि प्रदर्शित होगा:
static void Blah(Func<object> f)
{
Console.WriteLine(f().ToString());
}
static void Main()
{
Blah(() => 123);
}
मुझे आशा है कि आप इस बात से सहमत है कि इस के रूप में
static object Anon() { return (object)123; }
उत्पन्न किया जाना चाहिए और न
static int Anon() { return 123; }
क्योंकि बाद नहीं किया जा सकता Func<object>
में परिवर्तित! मुक्केबाजी निर्देश के लिए कहीं भी नहीं है, लेकिन ToString
पर कॉल f()
द्वारा संदर्भ प्रकार को वापस करने की अपेक्षा करता है।
इस प्रकार सामान्य नियम यह है कि लैम्ब्डा, जब एक छिपी विधि के रूप में संशोधित किया जाता है, तो उसके पास प्रतिनिधि प्रकार के रूपांतरण द्वारा रिटर्न प्रकार दिया जाना चाहिए।
साथ ही, लैम्ब्डा संस्करण में निर्दिष्ट करने का कोई तरीका है कि मैं वापसी मूल्य को ठोस प्रकार होना चाहता हूं? या एक स्थैतिक विधि को ऐसा करने का एकमात्र तरीका बुला रहा है?
निश्चित रूप से।
interface IThing {}
class Foo : IThing {}
delegate T ThingCreator<T>() where T : IThing;
public class Program
{
static void Test<T>(ThingCreator<T> tc) where T : IThing
{
Console.WriteLine(tc.Method.ReturnType);
}
public static void Main()
{
Test(() => new Foo());
}
}
यह अलग क्यों है?
क्योंकि प्रकार निष्कर्ष deduces कि T
Foo
है और इसलिए हम ThingCreator<Foo>
को लैम्ब्डा, लौट प्रकार Foo
है जो परिवर्तित कर रहे हैं। इसलिए उत्पन्न विधि Foo
लौटाती है, क्योंकि प्रतिनिधि प्रकार की उम्मीद है।
लेकिन रुकिए, आप कहते हैं ... मैं टेस्ट के हस्ताक्षर या ThingCreator
कोई चिंता नहीं की परिवर्तित नहीं कर सकता!
delegate T ThingCreator<T>() where T : IThing;
delegate IThing ThingCreator();
public class Program
{
static void Test(ThingCreator tc)
{
Console.WriteLine(tc.Method.ReturnType);
}
static ThingCreator DoIt<T>(ThingCreator<T> tc) where T : class, IThing
{
return tc.Invoke;
}
public static void Main()
{
Test(DoIt(() => new Foo()));
}
}
नीचे की ओर है कि अब अपने गैर सामान्य ThingCreator
प्रतिनिधियों में से हर एक एक प्रतिनिधि जो एक ThingCreator<T>
प्रतिनिधि, जो समय और स्मृति की बर्बादी का एक सा है कहता है है: आप अभी भी यह काम कर सकते हैं। लेकिन आपको वांछित वापसी प्रकार, और उस विधि के प्रतिनिधि को एक विधि बनाने के लिए टाइप अनुमान, विधि समूह रूपांतरण और लैम्ब्डा रूपांतरण मिलता है।
class
बाधा नोट करें। क्या आप देखते हैं कि उस बाधा क्यों होनी चाहिए? यह पाठक के लिए एक अभ्यास के रूप में छोड़ दिया गया है।
एक __static__ विधि एकमात्र तरीका नहीं है। आप एक गैर स्थैतिक भी उपयोग कर सकते हैं। उदाहरण के लिए 'Func f =() => नया Foo(); टेस्ट (एफ। इन्वोक); लेकिन असली सवाल यह है कि, आप एक (संभावित रूप से मल्टी-कास्ट) प्रतिनिधि उदाहरण पर '.Method.ReturnType' क्यों जांचते हैं? इसके लिए क्या उपयोग है; तुम क्यो फिकर करते हो? –
@ जेपे - एक तृतीय पक्ष लाइब्रेरी में एक सार्वजनिक एपीआई है जिसमें 'टेस्ट' जैसी विधि है। मुझे वास्तविक कार्य के संदर्भ के बजाय लैम्ब्डा पास करके साइड इफेक्ट की उम्मीद नहीं थी। यह पता लगाने के लिए खोदना था कि उन्होंने विधि के रिटर्न प्रकार की जांच की है। अगर यह मेरा अपना कोड था, तो मैं ऐसी चीज नहीं बनाऊंगा। –