2008-09-03 20 views
57

मैंने इस शब्द को सुना/पढ़ा है लेकिन इसका अर्थ यह नहीं है कि इसका क्या अर्थ है।सी # में डबल प्रेषण?

मुझे इस तकनीक का उपयोग कब करना चाहिए और मैं इसका उपयोग कैसे करूं? क्या कोई भी एक अच्छा कोड नमूना प्रदान कर सकता है?

+0

वर्तमान में यह करने का सबसे अच्छा तरीका है: https://blogs.msdn.microsoft.com/curth/2008/11/15/c-dynamic-and-multiple-dispatch/ –

+0

डबल प्रेषण का शानदार उदाहरण [रिच डोमेन मॉडल बनाने के लिए ऑब्जेक्ट कंपोजिशन लागू करना] (https://vimeo.com/195774910)। – jsuddsjr

+0

[डबल प्रेषण से सावधान रहें] (https://lostechies.com/derekgreer/2010/04/19/double-dispatch-is-a-code-smell/)। शायद आप बेहतर कोड रखरखाव के लिए इससे बच सकते हैं। –

उत्तर

54

विज़िटर पैटर्न ऑब्जेक्ट उन्मुख तरीके से डबल-प्रेषण करने का एक तरीका है।

यह तब उपयोगी होता है जब आप चुनना चाहते हैं कि संकलित समय के बजाय रनटाइम पर इसके प्रकार के आधार पर किसी दिए गए तर्क के लिए किस विधि का उपयोग करना है।

डबल प्रेषण एकाधिक प्रेषण का एक विशेष मामला है।

जब आप किसी ऑब्जेक्ट पर वर्चुअल विधि को कॉल करते हैं, जिसे सिंगल-डिस्पैच माना जाता है क्योंकि कौन सी वास्तविक विधि कहा जाता है, एकल ऑब्जेक्ट के प्रकार पर निर्भर करता है।

डबल प्रेषण के लिए, ऑब्जेक्ट के प्रकार और विधि दोनों एकमात्र तर्क के प्रकार को ध्यान में रखा जाता है। यह विधि ओवरलोड रिज़ॉल्यूशन की तरह है, सिवाय इसके कि तर्क प्रकार को संकलित समय पर स्थिर रूप से डबल-प्रेषण में रनटाइम पर निर्धारित किया जाता है।

एकाधिक प्रेषण में, एक विधि में कई तर्क पारित किए जा सकते हैं और कौन सा कार्यान्वयन उपयोग किया जाता है प्रत्येक तर्क के प्रकार पर निर्भर करता है। जिस प्रकार का मूल्यांकन किया जाता है वह आदेश भाषा पर निर्भर करता है। एलआईएसपी में, यह प्रत्येक प्रकार को पहले से आखिरी तक जांचता है।

एकाधिक प्रेषण वाली भाषाएं जेनेरिक फ़ंक्शंस का उपयोग करती हैं, जो केवल फ़ंक्शन डेलरेशन हैं और जेनेरिक विधियों की तरह नहीं हैं, जो टाइप पैरामीटर का उपयोग करती हैं।

सी # में डबल प्रेषण करने के लिए, आप एक एकमात्र उद्देश्य तर्क के साथ एक प्रणाली की घोषणा कर सकते हैं और विशिष्ट प्रकार के साथ फिर विशिष्ट तरीके:

using System.Linq; 

class DoubleDispatch 
{ 
    public T Foo<T>(object arg) 
    { 
     var method = from m in GetType().GetMethods() 
        where m.Name == "Foo" 
         && m.GetParameters().Length==1 
         && arg.GetType().IsAssignableFrom 
              (m.GetParameters()[0].GetType()) 
         && m.ReturnType == typeof(T) 
        select m; 

     return (T) method.Single().Invoke(this,new object[]{arg});   
    } 

    public int Foo(int arg) { /* ... */ } 

    static void Test() 
    { 
     object x = 5; 
     Foo<int>(x); //should call Foo(int) via Foo<T>(object). 
    } 
}  
+2

प्रतिबिंब के साथ LINQ का अद्भुत उपयोग - मैंने इसे पहले उन थकाऊ xxxInfo ऑब्जेक्ट्स पर लागू करने के लिए सोचा नहीं था। धन्यवाद! –

+24

मुझे यकीन नहीं है कि यह एक अच्छा विचार है। यह वास्तव में डबल प्रेषण को वास्तव में लागू नहीं करता है, मुझे संकलन-टी * को जानने की आवश्यकता है * प्रकार पैरामीटर निर्दिष्ट करने के लिए चीज़ का प्रकार क्या है !! आप सभी प्रतिबिंब कोड से भी परेशान नहीं हो सकते हैं और बस ऑब्जेक्ट को कास्ट कर सकते हैं। क्या मैं कुछ भूल रहा हूँ? – ljs

+4

यह डबल प्रेषण को कार्यान्वित करता है जिसमें यह ऑब्जेक्ट के रनटाइम प्रकार (डबलडिस्पेच से व्युत्पन्न) और विधि तर्क दोनों पर प्रेषण कर रहा है। वापसी प्रकार पर प्रतिबिंब का उपयोग मचानवाद को उप-वर्गों में विस्तारित करने के लिए किया जाता है, ताकि आप उप-वर्ग में "स्ट्रिंग फू (स्ट्रिंग)" जोड़ सकें और यह काम करेगा। –

1

डबल-प्रेषण Visitor pattern के लिए दूसरा नाम है।

मेरे पास एक लेख है जिसे मैंने कुछ साल पहले विज़िटर पैटर्न को लागू करने के लिए प्रतिबिंब का उपयोग करने के बारे में लिखा था। http://www.agileprogrammer.com/dotnetguy/articles/ReflectionVisitor.aspx

+10

लिंक टूटा हुआ प्रतीत होता है। क्या आप इसे ठीक कर सकते हैं? – Vertexwahn

11

खैर हे दोस्तों, कोड मार्क द्वारा पोस्ट की गई पूरी नहीं है और क्या काम नहीं कर रहा है।

तो tweaked और पूरा।

class DoubleDispatch 
{ 
    public T Foo<T>(object arg) 
    { 
     var method = from m in GetType().GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic) 
        where m.Name == "Foo" 
          && m.GetParameters().Length == 1 
          //&& arg.GetType().IsAssignableFrom 
          //     (m.GetParameters()[0].GetType()) 
          &&Type.GetType(m.GetParameters()[0].ParameterType.FullName).IsAssignableFrom(arg.GetType()) 
          && m.ReturnType == typeof(T) 
        select m; 


     return (T)method.Single().Invoke(this, new object[] { arg }); 
    } 

    public int Foo(int arg) 
    { 
     return 10; 
    } 

    public string Foo(string arg) 
    { 
     return 5.ToString(); 
    } 

    public static void Main(string[] args) 
    { 
     object x = 5; 
     DoubleDispatch dispatch = new DoubleDispatch(); 

     Console.WriteLine(dispatch.Foo<int>(x)); 


     Console.WriteLine(dispatch.Foo<string>(x.ToString())); 

     Console.ReadLine(); 
    } 
} 

धन्यवाद मार्क और डबल डिस्पैचर तर्ज पर अच्छा विवरण के लिए दूसरों

+0

मैं सहमत हूं। यह कोड पूर्ण है और दिखाता है कि वास्तव में क्या डबल प्रेषण है। चिह्न के उत्तर से स्पष्टीकरण और यह कोड पूरी तरह से एक साथ चला जाता है। –

+0

"कंसोल। लिखना नहीं होगा (प्रेषण.फू (x));" पैटर्न का लाभ लेने के लिए एक और अधिक गतिशील और उपयोगी तरीका हो? –

0

सी # 4 छद्म प्रकार dynamic जो क्रम (संकलन समय के बजाय) पर समारोह कॉल का समाधान करता है प्रस्तुत करता है। (यानी, अभिव्यक्ति का रनटाइम प्रकार उपयोग किया जाता है)। डबल- (या बहु-प्रेषण) को सरल बनाया जा सकता है:

class C { } 

static void Foo(C x) => Console.WriteLine(nameof(Foo)); 
static void Foo(object x) => Console.WriteLine(nameof(Object)); 

public static void Main(string[] args) 
{ 
    object x = new C(); 

    Foo((dynamic)x); // prints: "Foo" 
    Foo(x);   // prints: "Object" 
} 

अभिन्न प्रकारों के साथ सावधान रहें। चूंकि dynamic को System.Object के रूप में माना जाता है, यह उपर्युक्त उदाहरण में void Foo(int x) को कभी भी कॉल नहीं करेगा।

ध्यान दें कि dynamic का उपयोग करके आप संकलक को कोड के इस भाग की जांच करने के लिए एक स्थिर विश्लेषक को रोकते हैं। आपको ध्यान से dynamic पर विचार करना चाहिए।

संबंधित मुद्दे