2017-02-28 7 views
9

जहां तक ​​मुझे कक्षा sealed बनाने के बारे में पता है VTable में देखने से छुटकारा पाता है या मैं गलत हूं? यदि मैं कक्षा sealed बनाता हूं तो इसका मतलब यह है कि कक्षा पदानुक्रम में सभी वर्चुअल विधियों को भी sealed चिह्नित किया गया है?वर्चुअल टेबल से कैसे छुटकारा पाएं? मुहरबंद वर्ग

उदाहरण के लिए:

public class A { 
    protected virtual void M() { ........ } 
    protected virtual void O() { ........ } 
} 

public sealed class B : A { 
    // I guess I can make this private for sealed class 
    private override void M() { ........ } 
    // Is this method automatically sealed? In the meaning that it doesn't have to look in VTable and can be called directly? 

    // Also what about O() can it be called directly too, without VTable? 
} 
+1

नहीं, विधि कॉल अभी भी वर्चुअल होगा। – InBetween

+0

आप लगभग सही हैं - आपको विधि को 'मुहरबंद' के रूप में चिह्नित करने की आवश्यकता है, कक्षा नहीं। – Nat

+0

@Nat लेकिन जैसा कि मैंने नीचे टिप्पणी की - यह आलेख कहता है कि कक्षा को सील किया जा सकता है http://codebetter.com/patricksmacchia/2008/01/05/rambling-on-the-sealed-keyword/ मेरे लिए चिह्नित करना आसान है कक्षा प्रत्येक वर्चुअल विधि के बजाय मुहरबंद। –

उत्तर

2

"मुझे लगता है कि मैं इस मोहरबंद वर्ग के लिए निजी बना सकते हैं"

आप वंशानुगत पदानुक्रम में पहुँच संशोधक नहीं बदल सकते। इसका मतलब है कि यदि बेस क्लास में public विधि है तो आप इसे private या internal या protected व्युत्पन्न कक्षाओं में नहीं बना सकते हैं। आप संशोधक बदलने केवल यदि आप new के रूप में अपने प्रणाली की घोषणा कर सकते हैं:

private new void M() { ........ } 

जहां तक ​​मेरा सील vtable में ऊपर देखो से छुटकारा मिलता है या मैं गलत हूँ वर्ग बनाने पता?

मुहरबंद वर्ग पदानुक्रम में आखिरी है क्योंकि आप इससे प्राप्त नहीं कर सकते हैं। इस sealed कक्षा बेस क्लास से कुछ विधि ओवरराइड करते समय वर्चुअल टेबल sealed कक्षा के साथ उपयोग किया जा सकता है।

यदि मैं कक्षा को सील कर देता हूं तो इसका मतलब यह है कि कक्षा पदानुक्रम में सभी वर्चुअल विधियों को भी सील कर दिया गया है?

आप आईएल कोड देख सकते हैं:

.method family hidebysig virtual   // method is not marked as sealed 
    instance void M() cil managed 
{   
    .maxstack 8 

    IL_0000: nop 
    IL_0001: ret value 
} 

विधि sealed के रूप में चिह्नित नहीं है। भले ही आप इस विधि को sealed के रूप में स्पष्ट रूप से चिह्नित करें, आपको एक ही आईएल कोड मिलेगा।

इसके अलावा, sealedsealed कक्षा में विधि को चिह्नित करने का कोई कारण नहीं है। यदि वर्ग sealed है तो आप इसका वारिस नहीं कर सकते हैं, इसलिए आप इसके तरीकों का वारिस नहीं कर सकते हैं।

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

+0

प्रदर्शन के बारे में क्या? मुझे इन तरीकों की आवश्यकता है जो VTable में नहीं दिखें। मुझे पता है कि यह बहुत छोटी राशि है और शायद ज्यादातर मामलों में इससे कोई फर्क नहीं पड़ता है और यह विधि सील करने के डिजाइन कारण होना चाहिए। तो क्या मुझे VTable में दिखने से रोकने के लिए सील किए गए प्रत्येक विधि को चिह्नित करना होगा? –

+1

यदि आप 'मुहरबंद' वर्ग में 'मुहरबंद' के रूप में विधि चिह्नित करते हैं तो आपको एक ही आईएल मिल जाएगा। देखें: बिना सीलबंद '- http://prnt.sc/eecpnk, 'मुहरबंद' के साथ - http://prntscr.com/eecq2w –

+0

धन्यवाद, तो मुझे लगता है कि यह इस बात पर निर्भर करता है कि कक्षा सील कर दी गई है, तो वहां है इस आलेख के अनुसार विधि को गैर-वर्चुअल रूप से बुलाया जाएगा: http://codebetter.com/patricksmacchia/2008/01/05/rambling-on-the-sealed-keyword/ –

0

मुहरबंद मतलब है कि आप इससे प्राप्त नहीं कर सकते हैं या इसे ओवरराइड नहीं कर सकते हैं। यदि आप कक्षा बी से प्राप्त नहीं कर सकते हैं, तो आपके पास विधि एम ओवरराइड करने का कोई तरीका नहीं है क्योंकि लुकअप के लिए मुझे नहीं लगता कि आप इसे सहेजते हैं। आपके उदाहरण कॉलिंग विधि ओ में कक्षा ए से विधि को देखना होगा और इसे कॉल करना होगा। यह vtable के माध्यम से होता है।

0

कक्षा या विधि मुहरबंद बनाना कोई प्रभाव नहीं पड़ेगा, B.M() पर कोई भी कॉल आभासी होगा।

तो मुझे यकीन है कि क्यों यह इतना है, मैं अपने कहेंगे क्योंकि M()A में घोषित किया जाता है, अधिभावी यह विधि नहीं है था B करने के लिए "हैं"।

आप उत्पन्न कोड की IL का निरीक्षण किया, तो आप उस प्रासंगिक शिक्षा callvirt instance string namespace.A::M() है देखेंगे, और इसलिए, भले ही B बंद है, कॉल आभासी होना चाहिए।

2

ध्यान देने वाली पहली बात यह है कि सी # आमतौर पर किसी संदर्भ प्रकार पर वर्चुअल कॉल करता है, भले ही विधि वर्चुअल नहीं है। ऐसा इसलिए है क्योंकि एक सी # नियम है कि एक शून्य संदर्भ पर एक विधि को कॉल करना अवैध है जो .NET नियम नहीं है (कच्चे सीआईएल में यदि आप एक शून्य संदर्भ पर एक विधि कहते हैं और वह विधि स्वयं किसी फ़ील्ड तक नहीं पहुंचती है या वर्चुअल विधि, यह ठीक काम करता है) और callvirt का उपयोग उस नियम को लागू करने का एक सस्ता तरीका है।

सी # गैर आभासी उदाहरण के लिए call बजाय callvirt उत्पन्न होगा कुछ मामलों में जहां यह स्पष्ट है कि संदर्भ रिक्त नहीं है में कहता है। विशेष रूप से obj?.SomeMethod() के साथ ?. का अर्थ है कि एक नल-चेक पहले से ही हो रहा है, तो SomeMethod() वर्चुअल नहीं है, इसे call पर संकलित किया जाएगा। यह ?. के साथ होता है क्योंकि ?. संकलित करने के लिए कोड यह जांच कर सकता है जबकि यह if (obj != null){obj.SomeMethod();} के साथ नहीं होता है क्योंकि . संकलित कोड यह नहीं जानता है कि यह एक शून्य-जांच का पालन कर रहा है। शामिल तर्क बहुत स्थानीय है।

सीआईएल स्तर पर आभासी तरीकों के लिए वर्चुअल टेबल लुकअप को छोड़ना संभव है। इस प्रकार base कॉल काम करता है; callvirt की बजाय किसी विधि के कार्यान्वयन के आधार पर call पर संकलित किया गया। निर्माण obj?.SomeMethod() में विस्तार से जहां SomeMethod आभासी और मुहरबंद था (चाहे व्यक्तिगत रूप से या obj का प्रकार सील कर दिया गया था) तो यह सैद्धांतिक रूप से संभवतः call को सबसे व्युत्पन्न प्रकार के कार्यान्वयन के रूप में संकलित करना संभव होगा। हालांकि कुछ अतिरिक्त चेक जो विशेष रूप से किए जाने की आवश्यकता है यह सुनिश्चित करने के लिए कि यह अभी भी सही तरीके से काम करता है यदि घोषित प्रकार और मुहरबंद प्रकार के बीच पदानुक्रम में कक्षाएं ओवरराइड जोड़ती हैं या हटाती हैं। ऑप्टिमाइज़ेशन सुरक्षित होने के लिए इसे पदानुक्रम के कुछ वैश्विक ज्ञान की आवश्यकता होगी (और आश्वासन है कि ज्ञान नहीं बदलेगा, जिसका मतलब है कि वर्तमान में असेंबली में सभी प्रकार के संकलन किए जा रहे हैं)। और लाभ छोटा है। और अभी भी अधिकांश कारणों के लिए उपलब्ध नहीं है क्योंकि callvirt का उपयोग अधिकांश समय गैर-वर्चुअल कॉल पर भी किया जाता है।

मुझे नहीं लगता कि वहां कहीं भी है जहां sealed संकलक कैसे कॉल उत्पन्न करता है, और यह निश्चित रूप से इसे अधिकांश समय प्रभावित नहीं कर रहा है।

जिटर अधिक ज्ञान लागू करने के लिए स्वतंत्र है, लेकिन यदि कोई भी बहुत छोटा हो रहा है तो फिर अंतर। मैं निश्चित रूप से उन वर्गों को चिह्नित करने की अनुशंसा करता हूं जिन्हें आप जानते हैं उन्हें sealed के रूप में ओवरराइड नहीं किया जाएगा और यदि जिटर इसका उपयोग करता है तो यह बहुत अच्छा है, लेकिन मुख्य कारण यह है कि मैं अनुशंसा करता हूं कि यह प्रदर्शन नहीं बल्कि सहीता है। यदि आप कहीं ऐसी कक्षा को ओवरराइड करने का प्रयास करते हैं जिसे आपने sealed पर चिह्नित किया था तो या तो ए। आपने अभी डिज़ाइन को थोड़ा बदल दिया है और आपको पता था कि आपको sealed (.5 सेकेंड इसे हटाने के लिए काम करना होगा) या बी को हटा देना होगा। एक जगह में कुछ किया जो आपको यकीन था कि आप दूसरे में नहीं होंगे। पुनर्विचार का संक्षिप्त विराम होना अच्छा है।

यदि मैं कक्षा को सील कर देता हूं तो इसका मतलब यह है कि कक्षा पदानुक्रम में सभी आभासी तरीकों को भी सील कर दिया गया है?

उन्हें स्पष्ट रूप से चिह्नित किया गया है जैसा कि उन्हें स्पष्ट रूप से चिह्नित किया गया है।

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