2009-08-13 23 views
7

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

class GeneratedFoo 
{ 
    public void Write(string p) { /* do something */ } 
} 

सी # परियोजना में, हम इतना है कि हम MyFoo का एक अलग कार्यान्वयन में प्लग कर सकते हैं एक तरीका प्रदान करना चाहते हैं। इसलिए मैं GeneratedFoo

class MyFoo : GeneratedFoo 
{ 
    public new void Write(string p) { /* do different things */ } 
} 

से ली गई तो मैं एक CreateFoo विधि है कि या तो GeneratedFoo या MyFoo वर्ग का एक उदाहरण वापस आ जाएगी है MyFoo बनाने के लिए सोच रहा हूँ। हालांकि यह हमेशा जेनरेटेड फू में विधि को कॉल करता है।

GeneratedFoo foo = CreateFoo(); // if this returns MyFoo, 
foo.Write("1"); // it stills calls GeneratedFoo.Write 

यह निष्कासित है क्योंकि यह वर्चुअल विधि नहीं है। लेकिन मैं सोच रहा हूं कि व्युत्पन्न विधि कहने के लिए कोई तरीका है (एक हैक हो सकता है)।

धन्यवाद,
इयान

+0

"सार्वजनिक नया शून्य"? "नया" का उपयोग करता है जो मैंने पहले कभी नहीं देखा है। क्या यह भी वैध है? – abelenky

+0

'नया' यहां इंगित करता है कि आपने बेस क्लास से स्पष्ट रूप से 'कवर' विधि है, इसे ओवरराइड किए बिना (क्योंकि यह वर्चुअल नहीं है) - इसके बिना आपको वास्तव में कंपाइलर से चेतावनी मिल जाएगी। –

+0

अधिक विशिष्ट होने के लिए - जब आप व्युत्पन्न कक्षा में अपना नाम आधार के समान नाम देते हैं, और यह ओवरराइड विधि नहीं है, तो कंपाइलर्स आपको चेतावनी देता है कि आप अपनी विधि विरासत में सदस्य को छुपाते हैं (क्योंकि आप शायद ऐसा नहीं करना चाहते थे), लेकिन यदि आप इसके बारे में निश्चित हैं, तो आप 'नए' कीवर्ड का उपयोग करके संकलक को बताएं। –

उत्तर

6

विधि आभासी बनाने के लिए, कोई सक्षम होने के बिना। एक गैर वर्चुअल विधि संकलित समय पर स्थिर रूप से जुड़ा हुआ है और बदला नहीं जा सकता है।

1

यदि जेनरेट क्लास में वर्चुअल विधि नहीं है तो यह संभव नहीं है। यदि आप वर्चुअल के रूप में लिखें विधि उत्पन्न करने के लिए टूल को संशोधित कर सकते हैं तो MyFoo में लिखें विधि को अर्हता प्राप्त करने के लिए नए के बजाय कीवर्ड ओवरराइड का उपयोग करें। एक दूसरी विकल्प जेनरेटेड फू के स्रोत कोड को बदलने के लिए एक स्क्रिप्ट/मैक्रो लिखना होगा, जब उपकरण आपके निर्माण प्रक्रिया के हिस्से के रूप में वांछित विधियों से पहले "आभासी" स्ट्रिंग इंजेक्ट करने के बाद चलाया जाता है।

22

एडम ने आपको एक उत्तर दिया (सही एक)। अब यह हैक के लिए समय आप :)


class BaseFoo 
{ 
    public void Write() { Console.WriteLine("Hello simple world"); } 
} 

class DerFoo : BaseFoo 
{ 
    public void Write() { Console.WriteLine("Hello complicated world"); } 
} 

public static void Main() 
{ 
    BaseFoo bs = new DerFoo(); 
    bs.Write(); 

    bs.GetType().GetMethod("Write").Invoke(bs, null); 
} 

प्रिंटों बाहर के लिए पूछ रहे थे:

 
Hello simple world 
Hello complicated world 
+0

वहां असुरक्षित की कोई आवश्यकता नहीं है –

+0

ऐ, यह असुरक्षित यहां है क्योंकि मेरे पास कुछ "परीक्षण" परियोजनाएं हैं जिन्हें मैं वीएस में खोलता हूं जब मुझे कुछ वास्तव में अजीब कोड पकाते हैं, इसलिए मुख्य रूप से मुख्य असुरक्षित है, और मेरे पास भी बहुत सारे हैं वहाँ अजीब उपयोग है। –

+0

वैसे भी, असुरक्षितता के लिए असुरक्षित हटा दिया गया है (क्योंकि यह अभी अप्रचलित है), इसे टिप्पणी करने के लिए धन्यवाद। –

-1

एक दृष्टिकोण है कि आप वास्तव में सभी GeneratedFoo से ली गई कुछ नए वर्गों को परिभाषित करने के लिए किया जाएगा इस्तेमाल कर सकते हैं; उदाहरण:

public class MyFooBase : GeneratedFoo 
{ 
    public virtual void MyMethod() { ... } 
} 

public class MyFoo1 : MyFooBase { ... } 

public class MyFoo2 : MyFooBase { ... } 

यह आपको अनिवार्य रूप से आपके जेनरेट क्लास में आभासी तरीकों को जोड़ने की अनुमति देगा।

+0

लेकिन जेनरेट किए गए foo से गैर वर्चुअल विधि का आह्वान न करें क्योंकि यह वर्चुअल होगा। –

+0

लेकिन आप एक नई विधि लिख सकते हैं जो WAS वर्चुअल है और व्युत्पन्न कक्षा में nonvirtual कहा जाता है जिसे आप उस व्यवहार के लिए चाहते थे और व्युत्पन्न कक्षा में nonvirtual को कॉल नहीं किया था, जो उस व्यवहार नहीं होना चाहिए। –

3

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

हालांकि दोनों विधियां एक ही नाम साझा करती हैं, वे पूरी तरह से अलग तरीके हैं, यह कक्षा की विधि तालिका में एक अलग स्लॉट पर कब्जा करती है, जहां ओवरराइडिंग मौजूदा विधि को कक्षा की विधि तालिका में बदल देती है।

मेरा समाधान IFoo जैसे इंटरफेस का उपयोग करना होगा, या तो जेनरेट क्लास को संपादित करना होगा या प्रॉक्सी क्लास का उपयोग करना होगा जो IFoo को लागू करने के लिए जेनरेटेड फू के उदाहरण के लिए अपनी सभी विधि कॉल को प्रतिनिधि करता है।


public DelegatingFoo : IFoo 
{ 
    private GeneratedFoo foo; 

    public DelegatingFoo(GeneratedFoo foo) { this.foo = foo; } 
    public void Write(string p) { foo.Write(p); } 
} 
6

एक विस्तार विधि लिखें कि आपके व्युत्पन्न प्रकार के safecasts, और बदले कि संदर्भ के खिलाफ प्रणाली को बुलाती है।

public static class Extensions 
{ 
    public static void WriteFoo(this GeneratedFoo foo, string p) 
    { 
    MyFoo derived = foo as MyFoo; 
    if (derived != null) 
    { 
     derived.Write(p); 
    } 
    else 
    { 
     foo.Write(p); 
    } 
    } 
} 

तो

GeneratedFoo unknownFoo; 
unknownFoo.WriteFoo("win"); 

नायब से कॉल करने की: यह एक गंदा हैक है। एक स्पष्ट समाधान खुद से पूछना होगा क्यों आपको पहले स्थान पर new संशोधक का उपयोग करने की आवश्यकता है। Write(p) के अर्थ को ओवरलोड करने से आपके कोड को रखरखाव के लिए भ्रमित कर दिया जाएगा। आप इसे आसानी से public void WriteToTarget() घोषित कर सकते हैं या पहले स्थान पर भ्रम से बचने के लिए कुछ और विशिष्ट हो सकते हैं।

0

आपके निर्माण प्रणाली में एक कस्टम FX पुलिस नियम के बारे में क्या जोड़ा गया है?

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