2008-10-29 19 views
47

मैं यह नहीं लगता कि संभव है, लेकिन मैं इसे :) की जरूरत है तो हैअवहेलना डिफ़ॉल्ट निर्माता

मैं wsdl.exe कमांड लाइन से एक स्वत: जनरेट प्रॉक्सी फ़ाइल है विजुअल स्टूडियो 2008 द्वारा टूल।

प्रॉक्सी आउटपुट आंशिक कक्षाएं है। मैं उत्पन्न होने वाले डिफ़ॉल्ट कन्स्ट्रक्टर को ओवरराइड करना चाहता हूं। मैं कोड को संशोधित नहीं करता क्योंकि यह स्वतः उत्पन्न होता है।

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

मुझे पता है कि मैं आंशिक वर्ग से प्राप्त कर सकता हूं, लेकिन इसका मतलब यह होगा कि मुझे अपने सभी स्रोत कोड को नए माता-पिता वर्ग को इंगित करने के लिए बदलना होगा। मुझे ऐसा करने की ज़रूरत नहीं है।

कोई विचार, आसपास के काम, या हैक्स?

//Auto-generated class 
namespace MyNamespace { 
    public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol { 
     public MyWebService() { 
     string myString = "auto-generated constructor"; 
     //other code... 
     } 
    } 
} 

//Manually created class in order to override the default constructor 
namespace MyNamespace { 
    public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol { 
     public override MyWebService() { //this doesn't work 
     string myString = "overridden constructor"; 
     //other code... 
     } 
    } 
} 

उत्तर

36

यह संभव नहीं है: "सर्वश्रेष्ठ" जिस तरह से मैं के साथ आ सकता है एक डमी पैरामीटर के साथ एक ctor जोड़ सकते हैं और उपयोग करने वाले है। आंशिक कक्षाएं अनिवार्य रूप से एक ही कक्षा के हिस्से हैं; किसी विधि को दो बार या ओवरराइड नहीं किया जा सकता है, और इसमें कन्स्ट्रक्टर भी शामिल है।

आप निर्माता में एक विधि कॉल कर सकते हैं, और केवल इसे अन्य भाग फ़ाइल में लागू कर सकते हैं।

0

कुछ भी नहीं जो मैं सोच सकता हूं।

public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol 
{ 
    public override MyWebService(int dummy) 
    { 
     string myString = "overridden constructor"; 
     //other code... 
    } 
} 


MyWebService mws = new MyWebService(0); 
2

आप यह नहीं कर सकते हैं। मैं एक आंशिक विधि का उपयोग करने का सुझाव देता हूं जिसके बाद आप एक परिभाषा बना सकते हैं। कुछ ऐसा:

public partial class MyClass{ 

    public MyClass(){ 
     ... normal construction goes here ... 
     AfterCreated(); 
    } 

    public partial void OnCreated(); 
} 

शेष सुंदर आत्म व्याख्यात्मक होना चाहिए।

संपादित करें:

मैं यह भी कहना है कि आप इस सेवा है, जो आप तो कार्यक्रम के लिए, आप वास्तविक क्रियान्वयन के लिए संदर्भ के लिए की जरूरत नहीं है तो कर सकते हैं के लिए एक इंटरफेस को परिभाषित किया जाना चाहिए चाहते हैं। यदि आपने ऐसा किया तो आपके पास कुछ अन्य विकल्प होंगे।

2

मुझे लगता है कि आप PostSharp के साथ ऐसा करने में सक्षम हो सकते हैं, और ऐसा लगता है कि किसी ने आपको want for methods in generated partial classes किया है। मुझे नहीं पता कि यह आसानी से एक विधि लिखने की क्षमता में अनुवाद करेगा और उसके शरीर को कन्स्ट्रक्टर को प्रतिस्थापित कर दिया जाएगा क्योंकि मैंने इसे अभी तक शॉट नहीं दिया है लेकिन यह एक शॉट के लायक लगता है।

संपादित करें: this is along the same lines और यह भी दिलचस्प लग रहा है।

66

मेरे पास एक समान समस्या थी, मेरे जेनरेट कोड को डीबीएमएल फ़ाइल द्वारा बनाया जा रहा था (मैं लिंक-टू-एसक्यूएल कक्षाओं का उपयोग कर रहा हूं)।

जेनरेट क्लास में यह कन्स्ट्रक्टर के अंत में ऑनक्रेटेड() नामक आंशिक शून्य कहलाता है।

लंबी कहानी संक्षेप में, आप महत्वपूर्ण निर्माता सामान उत्पन्न वर्ग आप के लिए करता है (जो आप शायद करना चाहिए) रखना चाहते हैं, तो आपके आंशिक वर्ग में बनाने के निम्नलिखित:

partial void OnCreated() 
{ 
    // Do the extra stuff here; 
} 
+1

+1 सरल और सुरुचिपूर्ण समाधान। – James

+3

अब यह एक मतदान दुविधा है ... ओपी प्रश्न के साथ वास्तव में कुछ भी नहीं करना जो कि एल 2 एस के बारे में नहीं है, इसलिए ऑनक्रेटेड नहीं होगा लेकिन आपने मुझे टेबल के खिलाफ अपने सिर को टक्कर मार दी है, इसलिए मुझे लगता है। – Ryan

+0

@ रयान: मदद की खुशी है। धन्यवाद :-) –

12

हममम, मुझे लगता है कि एक सुरुचिपूर्ण समाधान निम्न होगा:

//* AutogenCls.cs file 
//* Let say the file is auto-generated ==> it will be overridden each time when 
//* auto-generation will be triggered. 
//* 
//* Auto-generated class, let say via xsd.exe 
//* 
partial class AutogenCls 
{ 
    public AutogenCls(...) 
    { 
    } 
} 



//* AutogenCls_Cunstomization.cs file 
//* The file keeps customization code completely separated from 
//* auto-generated AutogenCls.cs file. 
//* 
partial class AutogenCls 
{ 
    //* The following line ensures execution at the construction time 
    MyCustomization m_MyCustomizationInstance = new MyCustomization(); 

    //* The following inner&private implementation class implements customization. 
    class MyCustomization 
    { 
     MyCustomization() 
     { 
      //* IMPLEMENT HERE WHATEVER YOU WANT TO EXECUTE DURING CONSTRUCTION TIME 
     } 
    } 
} 

यह दृष्टिकोण कुछ कमियां (सब कुछ के रूप में) है:

  1. यह स्पष्ट नहीं है कि AutogenCls वर्ग की पूरी निर्माण प्रक्रिया के दौरान वास्तव में MyCustomization आंतरिक कक्षा के निर्माता को निष्पादित किया जाएगा।

  2. यदि MyCustomization क्लास के लिए अप्रत्याशित संसाधनों का निपटान सही तरीके से करने के लिए MyCustomization क्लास के लिए IDPosable इंटरफ़ेस को कार्यान्वित करने के लिए आवश्यक होगा, तो मुझे नहीं पता (अभी तक) MyCustomization को ट्रिगर करने के लिए कैसे करें। स्पर्श() विधि स्पर्श किए बिना AutogenCls.cs फ़ाइल ... (लेकिन जैसा कि मैंने कहा, "अभी तक ':)

लेकिन इस दृष्टिकोण स्वत: जनरेट कोड से महान जुदाई प्रदान करता है - पूरे अनुकूलन विभिन्न स्रोत कोड फ़ाइल में अलग है।

का आनंद :)

+0

स्टाइलकॉप इस समाधान के बारे में शिकायत करेगा: आपको अप्रयुक्त निजी चर से बचना चाहिए। –

+1

यह समाधान केवल एक स्थिर निर्माता प्रदान करता है: 'इस' तक कोई पहुंच नहीं। –

+0

'क्लास माई कस्टमाइज़ेशन' के बजाए एक छोटा सरलीकरण, आपको केवल 'कार्य _customization = TaskEx.Run (async() => {/ * अनुकूलन * /}) घोषित करने की आवश्यकता है; '। और यदि आपको इसकी आवश्यकता नहीं है तो 'async' को ओमेट किया जा सकता है। –

1

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

सबसे सरल उपाय शायद अतिरिक्त आंशिक वर्ग प्रति एक आंशिक 'निर्माता' विधि को जोड़ने के लिए है:

:

public partial class MyClass{ 

    public MyClass(){ 
     ... normal construction goes here ... 
     OnCreated1(); 
     OnCreated2(); 
     ... 
    } 

    public partial void OnCreated1(); 
    public partial void OnCreated2(); 
} 

आप एक दूसरे के बारे में नास्तिक होने के लिए आंशिक वर्गों चाहते हैं, आप प्रतिबिंब का उपयोग कर सकते

// In MyClassMyAspect1.cs 
public partial class MyClass{ 

    public void MyClass_MyAspect2(){ 
     ... normal construction goes here ... 

    } 

} 

// In MyClassMyAspect2.cs 
public partial class MyClass{ 

    public void MyClass_MyAspect1(){ 
     ... normal construction goes here ... 
    } 
} 

// In MyClassConstructor.cs 
public partial class MyClass : IDisposable { 

    public MyClass(){ 
     GetType().GetMethods().Where(x => x.Name.StartsWith("MyClass")) 
          .ForEach(x => x.Invoke(null)); 
    } 

    public void Dispose() { 
     GetType().GetMethods().Where(x => x.Name.StartsWith("DisposeMyClass")) 
          .ForEach(x => x.Invoke(null)); 
    } 

} 

लेकिन वास्तव में उन्हें आंशिक कक्षाओं के साथ काम करने के लिए कुछ और भाषा संरचनाएं जोड़नी चाहिए।

0

विजुअल स्टूडियो द्वारा उत्पन्न वेब सेवा प्रॉक्सी के लिए, आप आंशिक वर्ग में अपना स्वयं का कन्स्ट्रक्टर नहीं जोड़ सकते हैं (ठीक है आप कर सकते हैं, लेकिन इसे कॉल नहीं किया जाता है)। इसके बजाय, आप उस बिंदु पर अपने कोड में हुक करने के लिए [ऑनडिसेरियलाइज्ड] विशेषता (या [ऑनडिसेरियलाइजिंग]) का उपयोग कर सकते हैं जहां वेब प्रॉक्सी क्लास को तुरंत चालू किया जाता है।

using System.Runtime.Serialization; 

partial class MyWebService 
{ 
    [OnDeserialized] 
    public void OnDeserialized(StreamingContext context) 
    { 
     // your code here 
    } 
} 
+0

क्या यह वेब सेवा के लिए है या वस्तुओं को deserialized के रूप में वे एक सेवा कॉल में वापस कर रहे हैं? मैंने इसे अपने वेब सेवा क्लाइंट के आंशिक वर्ग में जोड़ने की कोशिश की लेकिन मेरी विधि को नहीं कहा जा रहा है ... –

4

वास्तव में, अब यह संभव है, अब आंशिक तरीकों को जोड़ा गया है। यहाँ डॉक है:

http://msdn.microsoft.com/en-us/library/wa80x488.aspx

असल में, विचार यह है कि आप घोषित करने और एक फाइल जहां आंशिक वर्ग को परिभाषित कर रहे में एक विधि कॉल कर सकते हैं, लेकिन वास्तव में उस फ़ाइल में विधि को परिभाषित नहीं। दूसरी फ़ाइल में, आप विधि को परिभाषित कर सकते हैं। यदि आप एक असेंबली का निर्माण कर रहे हैं जहां विधि परिभाषित नहीं की गई है, तो ORM फ़ंक्शन में सभी कॉल हटा देगा।

तो मामले में ऊपर इसे इस तरह दिखेगा:

// स्वत: निर्मित वर्ग

namespace MyNamespace { 
    public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol { 
     public MyWebService() { 
     string myString = "auto-generated constructor"; 
     OtherCode(); 
     } 
    } 
} 

partial void OtherCode(); 

// मैन्युअल आदेश डिफ़ॉल्ट निर्माता को ओवरराइड करने में श्रेणी का निर्माण

partial void OtherCode() 
{ 
    //do whatever extra stuff you wanted. 
} 

यह कुछ हद तक सीमित है, और इस विशेष मामले में, जहां आपके पास एक जेनरेट की गई फ़ाइल है जिसे आपको बदलने की आवश्यकता होगी, यह सही समाधान नहीं हो सकता है, लेकिन अन्य लोगों के लिए जो इस कोशिश पर ठोकर खा रहे हैं आंशिक कक्षाओं में कार्यक्षमता को ओवरराइड करने के लिए, यह काफी उपयोगी हो सकता है।

+5

बड़ी समस्या यह है कि ऑटो-जेनरेट कोड को इसे लागू करना होगा, लेकिन कई मामलों में मेरे पास ऑटोजन कोड पर नियंत्रण नहीं है – VoteCoffee

0

कभी-कभी आप पहुँच नहीं है या यह इस कारण से आप डिफ़ॉल्ट निर्माता किसी भी तरीकों कॉल करने के लिए नहीं हो सकता है के लिए डिफ़ॉल्ट निर्माता को बदलने के लिए, अनुमति नहीं है।

इस मामले में आप का उपयोग कर डिफ़ॉल्ट निर्माता कॉल करने के लिए एक डमी पैरामीटर के साथ एक और निर्माता बना सकते हैं और बनाने के इस नए निर्माता ": इस()"

public SomeClass(int x) : this() 
{ 
    //Your extra initialization here 
} 

और जब आप इस का एक नया उदाहरण बनाने वर्ग आप सिर्फ इस तरह डमी पैरामीटर पारित:

SomeClass objSomeClass = new SomeClass(0); 
2

समस्या यह है कि ओपी मिल गया है है कि वेब संदर्भ प्रॉक्सी किसी भी आंशिक तरीकों कि आप निर्माता अवरोधन करने का उपयोग कर सकते उत्पन्न नहीं करता है।

मैं एक ही समस्या में पड़ गए, और मैं सिर्फ WCF में नवीनीकृत नहीं कर सकते क्योंकि वेब सेवा है कि मैं कर रहा हूँ लक्ष्यीकरण इसका समर्थन नहीं करता।

मैं क्योंकि यह चपटा कर देंगे, तो क्या कभी किसी ने कोड पीढ़ी का आह्वान मैन्युअल स्वत: जनरेट कोड में संशोधन नहीं करना चाहता था।

मैं एक अलग कोण से समस्या को हल। मुझे पता था कि मेरे प्रारंभिकरण को अनुरोध से पहले करने की ज़रूरत थी, इसे निर्माण समय पर वास्तव में करने की ज़रूरत नहीं थी, इसलिए मैं इस तरह GetWebRequest विधि को ओवरराइड करता हूं।

protected override WebRequest GetWebRequest(Uri uri) 
{ 
    //only perform the initialization once 
    if (!hasBeenInitialized) 
    { 
     Initialize(); 
    } 

    return base.GetWebRequest(uri); 
} 

bool hasBeenInitialized = false; 

private void Initialize() 
{ 
    //do your initialization here... 

    hasBeenInitialized = true; 
} 

इसका कारण यह है कि यह हैकिंग ऑटो कोड उत्पन्न शामिल नहीं करता है एक अच्छा समाधान है, और यह एक SoapHttpClientProtocol स्वचालित रूप से जेनरेट प्रॉक्सी के लिए प्रारंभ लॉगिन प्रदर्शन के ओपी के सटीक उपयोग के मामले फिट बैठता है।

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