2013-05-08 14 views
10

निम्न पदानुक्रम को देखते हुए:जेनेरिक आवरण वर्ग

class A 
{ 
} 
class B : A 
{ 
    public void Foo() { } 
} 
class C : A 
{ 
    public void Foo() { } 
} 

यह एक तीसरी पार्टी पुस्तकालय है और मैं इसे बदल नहीं सकते। क्या कोई तरीका है कि मैं किसी प्रकार का 'जेनेरिक टेम्पलेटेड रैपर' लिख सकता हूं जो फू() विधि को कन्स्ट्रक्टर तर्क के रूप में पारित अनुचित वस्तु को अग्रेषित करेगा? मैं निम्नलिखित, जो कोई जेनरिक का उपयोग करता है और नहीं बल्कि बदसूरत लगता लेखन समाप्त हो गया:

class Wrapper 
    { 
     A a; 
     public Wrapper(A a) 
     { 
      this.a = a; 
     } 

     public void Foo() 
     { 
      if (a is B) { (a as B).Foo(); } 
      if (a is C) { (a as C).Foo(); } 
     } 

    } 

मैं Wrapper<T> where T : B or C जैसे कुछ टेम्पलेट बाधा अच्छा लगेगा।

+1

ही है मुझे लगता है मुख्य समस्या यह है कि 'फू है कि 'ए' में 'आभासी' नहीं है, है ना? – dasblinkenlight

उत्तर

15

तो AFoo नहीं है, आप की जरूरत है या तो dynamic का उपयोग करें (Jon Skeet's answer देखें) या lambdas साथ एक छोटी सी चाल का उपयोग करें और अधिक भार:

class Wrapper { 
    private Action foo; 
    public Wrapper(B b) { 
     foo =() => b.Foo(); 
    } 
    public Wrapper(C c) { 
     foo =() => c.Foo(); 
    } 
    public void Foo() { 
     foo(); 
    } 
} 

अब आप यह कर सकते हैं:

var wb = new Wrapper(new B()); 
wb.Foo(); // Call B's Foo() 
var wc = new Wrapper(new C()); 
wc.Foo(); // Call C's Foo() 

यह वही विधि पल Foo से कॉल करने के लिए पल Wrapper बनाई गई है करने के लिए कहा जाता है, संभवतः आप कुछ CPU चक्र बचत पर निर्णय बदलाव।

+0

सभी को धन्यवाद! मुझे लगता है कि मैं आपके समाधान के लिए जाता हूं क्योंकि अधिक फू-जैसे फ़ंक्शंस हैं, जिन्हें मैंने ब्रेवटी के लिए छोड़ा था। मुझे अपने कोड में कई बार रैपर का उपयोग करना पड़ता है और गतिशील भी बहुत ऑनलाइन समाधान लगता है। – amnezjak

7

नहीं, दो Foo विधियां पूरी तरह से असंबंधित हैं जहां तक ​​संकलक का संबंध है।

public void Foo() 
{ 
    dynamic d = a; 
    // Let's hope there's a suitable method at execution time! 
    d.Foo(); 
} 

जेनेरिक्स तुम यहाँ मदद नहीं करेगा, जहाँ तक मैं बता सकते हैं: ऐसा करने का व्यक्ति प्रकार के बारे में जानने के बिना सबसे आसान तरीका है के साथ शुरू करने के लिए गतिशील टाइपिंग उपयोग करने के लिए किया जाएगा। ऐसा कुछ इंटरफ़ेस नहीं है (कम से कम कोई भी जो आपने दिखाया है) जिसे आप T को बाधित कर सकते हैं।

आप एक Action में रूप में अच्छी तरह से पारित कर सकते हैं:

Wrapper wrapper = new Wrapper(b, b.Foo); 

जो इसे थोड़ा कम फोन करने वाले के लिए सुविधाजनक है, लेकिन बहुत सामान्य है ...

+1

यह स्कीट पाँच है। आप रॉक स्कीट। – JSJ

+0

जॉन के "एक्शन पासिंग" को डासब्लिंकलाइट के सुझाव और टी 4 टेम्पलेट के साथ विलय करें और आप शॉउडल को बहुत ही उचित और रखरखाव योग्य समाधान प्राप्त करें। – quetzalcoatl

0

मैं यह सुझाव के लिए अनिच्छुक हूँ, लेकिन आप पुस्तकालय संशोधित नहीं कर सकते के रूप में .. यदि यह प्रदर्शन महत्वपूर्ण नहीं है, याद dynamic कीवर्ड :)

class Wrapper 
{ 
    public dynamic theAorBorC; 

    public Wrapper(A a){theAorBorC=a;} 
    public Wrapper(B b){theAorBorC=b;} 
    public Wrapper(C c){theAorBorC=c;} 

    // or even... 
    // public Wrapper(object anything){theAorBorC=anything;} 

    public void CallFoo() 
    { 
     theAorBorC.Foo(); 
    } 
} 

संपादित करें: अन्य सभी मामलों में, संकलन-समय की जांच करने के लिए मैं व्यक्तिगत रूप से लैम्बडा का उपयोग करता हूं जो कि डैस्ब्लिंकलाइट दिखाया गया है। इसे टी 4 एस या किसी अन्य पाठ जनरेटर के साथ आसानी से स्वत: उत्पन्न किया जा सकता है।

0

आप समानांतर पदानुक्रम बना सकते हैं जिसमें रूट स्तर पर Foo() विधि शामिल है।
कारखाने के तरीकों का उपयोग करके आप किसी भी प्रकार के लिए एक रैपर उदाहरण बना सकते हैं। यह आप अपने A उदाहरण का सही प्रकार पता करने के लिए जब आप कारखाने विधि

abstract class Wrapper { 
    public abstract void Foo(); 

    //factory methods 
    public Wrapper FromB(B instance) { 
     return new WrapperB(instance); 
    } 
    public Wrapper FromC(C instance) { 
     return new WrapperB(instance); 
    } 
} 

class WrapperB { 
    private B instance {get; set;} 
    public WrapperB(B instance) { 
     this.instance = instance; 
    } 

    public void Foo() { 
     instance.Foo(); 
    } 
} 
class WrapperC { 
    private C instance {get; set;} 
    public WrapperC(C instance) { 
     this.instance = instance; 
    } 

    public void Foo() { 
     instance.Foo(); 
    } 
} 

संपादित करें फोन की जरूरत है काम करने के लिए: यह मूल रूप से के रूप में this answer

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