2009-01-26 15 views
6

यह, ओवरलोडिंग, अगर नहीं के रूप में ही है कर सकते हैं सी #क्या है - सिंगल और एकाधिक डिस्पैच (.NET के संबंध में)?

मैं एक ऐसी ही सवाल इसलिए पूछा के लिए प्रतिक्रियाओं को पढ़ लिया है में से प्रत्येक के प्रदान करते हैं और उदाहरण कृपया ... मैं प्रतिक्रियाओं इसे करने के लिए तैनात समझ में नहीं आया ।

इसी प्रश्न पूछा here

संपादित करें: नया "डायनामिक" के साथ में कीवर्ड सी # 4.0 ... इस भाषा "बहु प्रेषण" सक्षम होगा?

उत्तर

5

सी # है एकल प्रेषण का उपयोग करता है, जिसमें अधिभारित विधियां शामिल हैं। आप कोड है जब

stringBuilder.Append(parameter); 

डिस्पैचर सभी तरीकों stringbuilder की क्लास पर परिभाषित पर लग रहा है, और सही एक पाता है।

एकाधिक प्रेषण उदाहरण के लिए, आइए प्रोलॉग देखें (जो कि मैं सोच सकता हूं)। आप इस तरह के रूप में prolog में एक समारोह को परिभाषित कर सकते हैं:

func(Arg1, Arg2) :- ....body.... 

यह किसी भी वर्ग के अंदर लेकिन एक वैश्विक दायरे में परिभाषित नहीं है। फिर, आप किसी भी दो तर्कों पर func(Arg1, Arg2) पर कॉल कर सकते हैं और यह फ़ंक्शन कॉल किया जाएगा। आप अधिक भार की तरह कुछ चाहते हैं, आप समारोह के अंदर तर्क प्रकारों को मान्य करने के लिए, और इसे परिभाषित कई बार किया है:

func(Arg1, Arg2) :- is_number(Arg1), is_string(Arg2), ....body.... 
func(Arg1, Arg2) :- is_string(Arg1), is_list(Arg2), ....body.... 
func(Arg1, Arg2) :- is_number(Arg1), is_list(Arg2), ....body.... 

फिर, किसी भी दो तर्क प्रकारों आप भेजना होगा दोनों की जाँच की जानी होगा - जो एक से अधिक प्रेषण है अंश।

संक्षेप में, एकल प्रेषण केवल पहले तर्क (हमारे पहले उदाहरण, स्ट्रिंगबिल्डर) में परिभाषित विधियों को देखता है, फिर अन्य तर्कों का उपयोग करके कॉल करने के लिए सही ओवरलोड को हल करता है। एकाधिक प्रेषण में वैश्विक दायरे में परिभाषित विधियों/कार्यों के तरीके हैं और ओवरलोड रिज़ॉल्यूशन के दौरान सभी तर्कों का व्यवहार करते हैं।

मुझे आशा है कि मैं अपने आप को स्पष्ट कर दिया है, यह एक बहुत ही कठिन विषय है।


अद्यतन: मैं उल्लेख करने के लिए, कई प्रेषण क्रम में क्या होता है, जबकि एकल प्रेषण संकलन समय पर होता है भूल गया।
अद्यतन # 2: जाहिर है, यह सच नहीं था।

+0

में असुविधाजनक रूप से दूर था मेरी पसंदीदा भाषाओं में से एक। उम्मीद है कि मुझे भविष्यवाणी मिल गई है, हालांकि मैंने वर्षों से इसका इस्तेमाल नहीं किया है। – configurator

+0

दोनों एकल और एकाधिक प्रेषण या तो संकलन समय या रनटाइम पर किया जा सकता है। गतिशील प्रेषण रनटाइम पर बाध्यकारी कोड के लिए शब्द है। –

+0

@ बिल: हाँ, लेकिन एकाधिक प्रेषण के लिए उपयोग किए जाने वाले प्रकार रनटाइम प्रकार हैं और एकल प्रेषण (तर्क के लिए) के लिए उपयोग किए जाने वाले प्रकार संकलित समय प्रकार हैं। क्या मैं यहाँ गलत हूँ? – configurator

1

एकल/एकाधिक प्रेषण एक प्रकार का रन-टाइम ओवरलोडिंग है। एकल प्रेषण को आमतौर पर आभासी कार्यों के रूप में जाना जाता है। जब आप वर्चुअल फ़ंक्शन को कॉल करते हैं तो सटीक फ़ंक्शन को ऑब्जेक्ट के रन-टाइम प्रकार के आधार पर तय किया जाता है। डबल प्रेषण वही बात है, जो दो वस्तुओं के साथ काम करने के लिए बढ़ाया जाता है - आमतौर पर this पैरामीटर और दूसरा पैरामीटर। आप विस्टर पैटर्न का उपयोग करके बहुत अधिक कठिनाई के बिना इसे कार्यान्वित कर सकते हैं। एकाधिक प्रेषण आगे इस पैरामीटर को अधिक पैरामीटर तक बढ़ाता है, लेकिन सी # जैसी भाषाओं में लागू करना काफी कठिन है (ऐसा नहीं है कि यह नहीं किया जा सकता है, यह मुश्किल है)। कुछ भाषाएं बॉक्स के ठीक बाहर इस क्षमता को लागू करती हैं।

उदा .NET में, ToString() फ़ंक्शन

// Single dispatch 
Object o = GetSomeObject(); // Return SomeType casted to Object. 
o.ToString(); // Call SomeType::ToString instead of just Object::ToString 

// Double dispatch (this version won't work in C#) 
Shape s1 = GetSquare(); 
Shape s2 = GetCircle(); 
s1.Intersects(s2); // If C# supported double dispatch, this would call Square::Intersects(Circle) not Square::Intersects(Shape) 
2

मल्टी प्रेषण विधि ओवरलोडिंग से संबंधित है एक प्रेषण का एक उदाहरण है लेकिन एक ही नहीं है। पूर्व एक गतिशील रनटाइम निर्णय है, बाद वाला एक स्थिर संकलन निर्णय है। निस्संदेह एक लचीलापन लाभ है, लेकिन इसलिए बहु-प्रेषण के लिए एक प्रदर्शन लागत।

AFAIK एक भाषा या तो दोनों का समर्थन कर सकती है, लेकिन दोनों नहीं, हालांकि दोनों को अनुकरण किया जा सकता है (बहु-प्रेषण आगंतुकों के साथ अनुकरण किया जा सकता है)। सी # संकलन समय पर डेटाटाइप निर्धारित करता है और इसलिए बहु-प्रेषण भाषा नहीं है, इसलिए कोई उदाहरण संभव नहीं है।

(चेतावनी: मैं इस पर 100% नहीं कर रहा हूँ)


परिशिष्ट: वास्तव में विकिपीडिया इस जो सुंदर पूरी तरह से लगता है पर एक article, उह और एक उपयोगी लिस्प उदाहरण

+0

सी # 4.0 में नए "गतिशील" कीवर्ड के साथ ... क्या यह भाषा "बहु प्रेषण" सक्षम करेगा? – Developer

+0

@ निक, बिल्कुल नहीं, लेकिन यह बहुत करीब होगा। – configurator

+0

बिल्कुल मुझे विश्वास है कि – annakata

1

OO में पाठ languaes:

SomeType b; 
a = b.Foo(c, d) 

मतलब है कि वस्तु ख के साथ मानकों ग और घ संदेश फू पारित किया जा रहा है। एकल प्रेषण का अर्थ है कि इस प्रणाली का केवल एक पहलू रनटाइम पर निर्धारित करने के लिए ज़िम्मेदार है (संभावित रूप से कई) विधियों को वास्तव में बुलाया जाएगा।

मॉडल जावा, सी # और अधिकांश अन्य OO भाषाओं का उपयोग यह है कि केवल 'बी' के क्रम प्रकार 'तय' के लिए क्या वास्तविक विधि कॉल है हो जाता है। तो यदि आपके पास कुछ प्रकार के दो कार्यान्वयन हैं, जिनमें से दोनों फू का एक अलग कार्यान्वयन प्रदान करते हैं, तो निर्णय लेने के लिए निर्णय केवल उस बिंदु पर आधारित होता है जिस पर बी प्रकार उस बिंदु पर होता है। यदि अनेक हैं भार के फू की तो निर्णय करने के लिए उपयोग किए जाने वाले ओवरलोड एक संकलन समय संकलन समय पर आधारित ख, ग और घ के प्रकार पता निर्णय है।

यह एकल प्रेषण, पसंद का एक बिंदु ख के साथ जुड़े प्रकार प्रणाली है तो है।

एकाधिक डिस्पैच हैं, कार्यावधि में है, जो विधि कॉल करने का फैसला करने के ख, ग और घ के क्रम प्रकार की अनुमति देते हैं (ऐसा निर्णय अनिवार्य रूप से और अधिक जटिल है)।

एक और गतिशील प्रणाली में जहां अच्छी तरह से परिभाषित प्रकार की अवधारणा अधिक तरल पदार्थ है (सी ++/जावा/सी # से प्राप्त विरासत मॉडल की बजाय प्रोटोटाइप पर आधारित एक प्रणाली कहें) तो निर्णय लेने का तरीका क्या होगा इसके बजाय वास्तविक उदाहरण बी, सी और डी तक पूरी तरह से हो।

0
#include <iostream> 

class Pet { 
}; 

class Cat: public Pet { 
}; 

class Dog: public Pet { 
}; 

class Human { 
}; 

class Man : public Human { 
     public: 
       void Kick(Cat& victim); 
       void Kick(Dog& victim); 
}; 

class Woman : public Human { 
     public: 
       void Kick(Cat& victim); 
       void Kick(Dog& victim); 
}; 

void Man::Kick(Cat& victim) { 
     std::cout << "Meow!!!" << std::endl; 
} 

void Woman::Kick(Cat& victim) { 
     std::cout << "I won't kick a cat" << std::endl; 
} 

void Man::Kick(Dog& victim) { 
     std::cout << "I won't kick a dog" << std::endl; 
} 

void Woman::Kick(Dog& victim) { 
     std::cout << "Woof!!!" << std::endl; 
} 

int main(int argc, char** argv) { 
     Man kicker; 
     Dog victim; 
     Pet zoo[] = { victim }; 
     kicker.Kick(victim); 
//  kicker.Kick(zoo[0]); // No multimethods 
     return 0; 
} 

अब के रूप में, सी ++ रनटाइम पर समझ नहीं है कि क्या एक Pet वास्तव में एक Cat या एक Dog है।

यदि रनटाइम पर ऐसा करने का कोई तरीका था (ताकि ऊपर दिया गया कोड असम्बद्ध टिप्पणी के साथ संकलित होगा), सी ++ को एकाधिक प्रेषण या बहुआयामी का समर्थन करने के लिए कहा जाएगा।

5

एकाधिक प्रेषण एक अधिक भार के "फार्म" ...

उदाहरण के लिए है, सी # एकल प्रेषण है क्योंकि अगर काम करता है केवल एक तर्क, "इस" सूचक के आधार पर को क्या नाम विधि। आप इस तरह से कुछ है जब:

Base base= new Derived(); 
base.DoSomething(); 

विधि Derived.DoSomething कहा जाता है, भले ही आप इसे आधार सूचक के माध्यम से कहा जाता है।अब, अगर हम निम्नलिखित है:

class Derived : Base 
{ 
    public override void Process(Stream stream); 
    public override void Process(FileStream stream); 
    public override void Process(MemoryStream stream); 
} 

और हम ऐसा करते हैं:

Stream stream= new MemoryStream(...); 
Base b= new Derived(); 
b.Process(stream); 

फिर हम के रूप में सी # पर एक एकल प्रेषण करता प्रक्रिया (स्ट्रीम) Derived से विधि कॉल करेंगे ऑब्जेक्ट पॉइंटर (बी) और उसके बाद संकलित समय की जानकारी का उपयोग यह तय करने के लिए करता है कि किस विधि को कॉल करना है। भले ही धारा एक मेमोरीस्ट्रीम है, एक एकल प्रेषण प्रणाली इसे अनदेखा कर देगी।

एक बहु-प्रेषण प्रणाली में ऑब्जेक्ट पॉइंटर को देखा जाएगा (सी # में) और तर्कों के रनटाइम प्रकार की जांच की जाएगी। उपर्युक्त उदाहरण में, क्योंकि स्ट्रीम वास्तव में एक मेमोरीस्ट्रीम है, सिस्टम प्रक्रिया (मेमोरीस्ट्रीम) विधि को कॉल करेगा।

+0

के माध्यम से स्पष्टीकरण सही है, कोड में एक त्रुटि है; बी। प्रोसेस को बुलाया नहीं जा सकता है अगर यह केवल व्युत्पन्न में परिभाषित किया गया है। – configurator

+1

यह एक महान उदाहरण है! –

0

सी # में 4.0 मुल्टीमेथड्स नए गतिशील कीवर्ड के साथ सक्षम हैं:

प्रणाली का उपयोग करते हुए; नाम स्थान उदाहरण { वर्ग व्हील { सार्वजनिक शून्य RepairWhell() {} }

class Chassis 
{ 
    public void RepairChassis() { } 
} 

class Engine 
{ 
    public void RepairEngine() { } 
} 

class CarWorkshop 
{ 
    public string Repair(Wheel value) 
    { 
     value.RepairWhell(); 
     return "wheel repaired"; 
    } 
    public string Repair(Chassis value) 
    { 
     value.RepairChassis(); 
     return "chassis repaired"; 
    } 
    public string Repair(Engine value) 
    { 
     value.RepairEngine(); 
     return "engine repaired"; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     dynamic carWorkshop = new CarWorkshop(); 

     var whell = new Wheel(); 
     var chassis = new Chassis(); 
     var engine = new Engine(); 

     Console.WriteLine(carWorkshop.Repair(whell)); 
     Console.WriteLine(carWorkshop.Repair(chassis)); 
     Console.WriteLine(carWorkshop.Repair(engine)); 
     Console.ReadLine(); 
    } 
} 

}

गतिशील मुल्टीमेथड्स, एक बहुत ही शक्तिशाली प्रतिमान, सी # में परिचय।

0

क्षमा करें, उदाहरण मैंने इसे गलत होने से पहले दिया था। सही संस्करण नहीं था:

class Wheel 
{ 
    public void RepairWhell() { } 
} 

class Chassis 
{ 
    public void RepairChassis() { } 
} 

class Engine 
{ 
    public void RepairEngine() { } 
} 

class CarWorkshop 
{ 
    public string Repair(Wheel value) 
    { 
     value.RepairWhell(); 
     return "wheel repaired"; 
    } 
    public string Repair(Chassis value) 
    { 
     value.RepairChassis(); 
     return "chassis repaired"; 
    } 
    public string Repair(Engine value) 
    { 
     value.RepairEngine(); 
     return "engine repaired"; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var carWorkshop = new CarWorkshop(); 

     dynamic whell = new Wheel(); 
     dynamic chassis = new Chassis(); 
     dynamic engine = new Engine(); 

     Console.WriteLine(carWorkshop.Repair(whell)); 
     Console.WriteLine(carWorkshop.Repair(chassis)); 
     Console.WriteLine(carWorkshop.Repair(engine)); 
     Console.ReadLine(); 
    } 
} 

तो एवर यह हाँ है। सी # बहु प्रेषण प्रदान करता है।

0

आप सी # में बहु-प्रेषण को लागू करने के लिए गतिशील कीवर्ड का उपयोग कर सकते हैं।

interface IA { } 
interface IB { } 
class CA1 : IA {} 
class CA2 : IA {} 
class CA11 : CA1 {} 
class CB1 : IB {} 
class CB2 : IB {} 

class MD 
{ 
    public enum X { X } ; 
    public static void Foo(IA a, IB b, X dispatch = X.X) { Foo((dynamic)a, (dynamic)b); } 
    static void Foo(IA a, IB b) { Console.WriteLine("IA IB"); } 
    static void Foo(CA1 a, CB1 b) { Console.WriteLine("CA1 CB1"); } 
    static void Foo(CA2 a, CB1 b) { Console.WriteLine("CA2 CB1"); } 
    static void Foo(CA1 a, CB2 b) { Console.WriteLine("CA1 CB2"); } 
    static void Foo(CA2 a, CB2 b) { Console.WriteLine("CA2 CB2"); } 
    static void Foo(CA11 a, CB2 b) { Console.WriteLine("CA11 CB2"); } 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     var a1 = new CA1(); 
     var a11 = new CA11(); 
     var a2 = new CA2(); 
     var b1 = new CB1(); 
     var b2 = new CB2(); 
     MD.Foo(a1, b1); 
     MD.Foo(a2, b1); 
     MD.Foo(a1, b2); 
     MD.Foo(a2, b2); 
     MD.Foo(a11, b1); 
     MD.Foo(a11, b2); 
    } 
} 

फू के संकल्प ((गतिशील) एक, (गतिशील) ख)) क्रम में किया, और 'एक' और 'बी' की ठोस प्रकार के आधार पर अतिभारित फू तरीकों में से एक का चयन करता है।

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