बॉक्सिंग की घटना C # में


85

मैं उन सभी स्थितियों को इकट्ठा करने की कोशिश कर रहा हूं जिनमें C # में मुक्केबाजी होती है:

  • टाइप करने के लिए मान परिवर्तित करना System.Object:

    struct S { }
    object box = new S();
    
  • टाइप करने के लिए मान परिवर्तित करना System.ValueType:

    struct S { }
    System.ValueType box = new S();
    
  • टाइप करने के लिए एन्यूमरेशन प्रकार का मान परिवर्तित करना System.Enum:

    enum E { A }
    System.Enum box = E.A;
    
  • इंटरफ़ेस संदर्भ में मान प्रकार परिवर्तित करना:

    interface I { }
    struct S : I { }
    I box = new S();
    
  • C # स्ट्रिंग संघनन में मूल्य प्रकारों का उपयोग करना:

    char c = F();
    string s1 = "char value will box" + c;
    

    नोट:char प्रकार के स्थिरांक का संकलन समय पर किया जाता है

    ध्यान दें: संस्करण 6.0 सी # संकलक के बाद से अनुकूलन संयोजन शामिल bool, char, IntPtr, UIntPtrप्रकार

  • मान प्रकार आवृत्ति विधि से प्रतिनिधि बनाना:

    struct S { public void M() {} }
    Action box = new S().M;
    
  • मूल्य प्रकारों पर गैर-ओवरराइड वर्चुअल तरीकों को कॉल करना:

    enum E { A }
    E.A.GetHashCode();
    
  • के तहत C # 7.0 निरंतर पैटर्न का उपयोग करना isअभिव्यक्ति के :

    int x = …;
    if (x is 42) { … } // boxes both 'x' and '42'!
    
  • सी # टपल प्रकार रूपांतरण में बॉक्सिंग:

    (int, byte) _tuple;
    
    public (object, object) M() {
      return _tuple; // 2x boxing
    }
    
  • objectमूल्य प्रकार के डिफ़ॉल्ट मानों के साथ वैकल्पिक पैरामीटर :

    void M([Optional, DefaultParameterValue(42)] object o);
    M(); // boxing at call-site
    
  • के लिए असंबंधित सामान्य प्रकार के मूल्य की जाँच करना null:

    bool M<T>(T t) => t != null;
    string M<T>(T t) => t?.ToString(); // ?. checks for null
    M(42);
    

    नोट: इसे JIT द्वारा कुछ .NET रनटाइम्स में ऑप्टिमाइज़ किया जा सकता है

  • / संचालकों के structसाथ असंबद्ध या सामान्य प्रकार का परीक्षण मूल्य टाइप करें :isas

    bool M<T>(T t) => t is int;
    int? M<T>(T t) => t as int?;
    IEquatable<T> M<T>(T t) => t as IEquatable<T>;
    M(42);
    

    नोट: इसे JIT द्वारा कुछ .NET रनटाइम्स में ऑप्टिमाइज़ किया जा सकता है

क्या मुक्केबाजी की कोई और स्थितियां हैं, शायद छिपी हुई हैं, जिसे आप जानते हैं?


2
मैंने कुछ समय पहले इससे निपटा, और यह काफी दिलचस्प पाया: FxCop का उपयोग करके बॉक्सिंग का पता लगाना (संयुक्त राष्ट्र)
जॉर्ज डकेट

आपके द्वारा दिखाए गए बहुत अच्छे रूपांतरण। वास्तव में मैं दूसरा नहीं जानता था या शायद कभी कोशिश नहीं की थी :) धन्यवाद
ज़ेनवल्कर

12
यह सामुदायिक विकि प्रश्न होना चाहिए
Sly

2
अशक्त प्रकारों के बारे में क्या? private int? nullableInteger
एलनसन

1
@allansson, nullable प्रकार केवल मान प्रकार के होते हैं
कंट्रोलफ्लो

जवाबों:


42

यह एक महान सवाल है!

बॉक्सिंग ठीक एक कारण से होता है: जब हमें किसी मूल्य प्रकार के संदर्भ की आवश्यकता होती है । आपके द्वारा सूचीबद्ध सब कुछ इस नियम में आता है।

उदाहरण के लिए चूंकि ऑब्जेक्ट एक संदर्भ प्रकार है, इसलिए ऑब्जेक्ट प्रकार के ऑब्जेक्ट को कास्टिंग करने के लिए एक मूल्य प्रकार के संदर्भ की आवश्यकता होती है, जो बॉक्सिंग का कारण बनता है।

यदि आप हर संभावित परिदृश्य को सूचीबद्ध करना चाहते हैं, तो आपको डेरिवेटिव भी शामिल करना चाहिए, जैसे कि एक ऐसी विधि से मान प्रकार लौटना जो ऑब्जेक्ट या इंटरफ़ेस प्रकार लौटाता है, क्योंकि यह स्वचालित रूप से ऑब्जेक्ट / इंटरफ़ेस के लिए मान प्रकार डाल देता है।

वैसे, आपके द्वारा पहचाने जाने वाले स्ट्रिंग संघनन का मामला भी कास्टिंग से ऑब्जेक्ट तक जाता है। + ऑपरेटर को संकलक द्वारा स्ट्रिंग के कॉनैट विधि के लिए एक कॉल में अनुवाद किया जाता है, जो आपके द्वारा पारित मूल्य प्रकार के लिए एक ऑब्जेक्ट को स्वीकार करता है, इसलिए ऑब्जेक्ट को कास्टिंग करना और इसलिए बॉक्सिंग होता है।

वर्षों से मैंने हमेशा डेवलपर्स को सलाह दी है कि वे हर एक मामले को याद रखने के बजाए बॉक्सिंग के लिए एकल कारण (ऊपर निर्दिष्ट) याद रखें, क्योंकि सूची लंबी है और याद रखना कठिन है। यह इस बात की समझ को भी बढ़ावा देता है कि कंपाइलर हमारे C # कोड के लिए क्या उत्पन्न करता है (उदाहरण के लिए + स्ट्रिंग पर कॉल String.Concat पर)। जब संकलक उत्पन्न करता है और यदि बॉक्सिंग होती है, तो आप संदेह में हैं, आप IL Disassembler (ILDAS3.exe) का उपयोग कर सकते हैं। आमतौर पर आपको बॉक्स ओपकोड की तलाश करनी चाहिए (बॉक्सिंग होने पर भी एक ही मामला हो सकता है, हालांकि आईएल में बॉक्स ओपकोड, नीचे और अधिक विवरण शामिल नहीं है)।

लेकिन मैं इस बात से सहमत हूं कि कुछ मुक्केबाजी की घटनाएं कम स्पष्ट हैं। आपने उनमें से एक को सूचीबद्ध किया है: एक मूल्य प्रकार के गैर-ओवरराइड विधि को कॉल करना। वास्तव में, यह एक और कारण के लिए कम स्पष्ट है: जब आप IL कोड की जांच करते हैं तो आपको बॉक्स opcode नहीं दिखता है, लेकिन बाधा opcode है, इसलिए IL में भी यह स्पष्ट नहीं है कि मुक्केबाजी होती है! मैं सटीक विवरण में नहीं मिलेगा कि इस उत्तर को और अधिक लंबा होने से क्यों रोका जाए ...

कम स्पष्ट मुक्केबाजी के लिए एक और मामला एक संरचना से बेस क्लास पद्धति को कॉल करते समय होता है। उदाहरण:

struct MyValType
{
    public override string ToString()
    {
        return base.ToString();
    }
}

यहाँ ToString ओवरराइड है, इसलिए MyValType पर ToString को कॉल करना बॉक्सिंग उत्पन्न नहीं करेगा। हालाँकि, कार्यान्वयन आधार को ToString कहता है और जिसके कारण बॉक्सिंग (IL की जाँच करें!) होता है।

वैसे, ये दो गैर-स्पष्ट मुक्केबाजी परिदृश्य भी ऊपर एकल नियम से प्राप्त होते हैं। जब किसी मान प्रकार के आधार वर्ग पर एक विधि लागू की जाती है, तो इस खोजशब्द के लिए कुछ होना चाहिए । चूंकि मान प्रकार का आधार वर्ग एक संदर्भ प्रकार (हमेशा) होता है, इसलिए इस कीवर्ड को एक संदर्भ प्रकार का संदर्भ देना चाहिए, और इसलिए हमें एक मूल्य प्रकार के संदर्भ की आवश्यकता है और इसलिए एकल नियम के कारण बॉक्सिंग होती है।

यहां मेरे ऑनलाइन .NET पाठ्यक्रम के अनुभाग से एक सीधा लिंक है जो बॉक्सिंग के बारे में विस्तार से चर्चा करता है: http://motti.me/mq

यदि आप केवल अधिक उन्नत मुक्केबाजी परिदृश्यों में रुचि रखते हैं, तो यहां एक सीधा लिंक है (हालांकि ऊपर लिंक आपको वहां ले जाएगा और साथ ही साथ यह अधिक बुनियादी सामान पर चर्चा करता है): http://motti.me/mu

आशा है कि ये आपकी मदद करेगा!

Motti


1
यदि किसी ToString()विशेष मूल्य प्रकार पर कॉल किया जाता है जो इसे ओवरराइड नहीं करता है, तो क्या कॉल साइट पर मूल्य प्रकार को बॉक्स किया जाएगा, या ऑटो-जेनरेट किए गए ओवरराइड के लिए विधि को (बॉक्सिंग के बिना) भेजा जाएगा जो श्रृंखला के साथ कुछ भी नहीं है (के साथ) बॉक्सिंग) आधार विधि के लिए?
सुपरकैट

@supercat baseवैल्यू टाइप में कॉल करने वाले किसी भी तरीके को कॉल करने से बॉक्सिंग हो जाएगी। इसमें वर्चुअल तरीके शामिल हैं जो संरचना द्वारा ओवरराइड नहीं किए गए हैं और वे Objectतरीके जो बिल्कुल आभासी नहीं हैं (जैसे GetType())। इस प्रश्न को देखें ।
फाक गेर

@ ResultafakGür: मुझे पता है कि अंतिम परिणाम मुक्केबाजी का होगा। मैं सटीक तंत्र के बारे में सोच रहा था जिसके माध्यम से ऐसा होता है। चूंकि कंपाइलर जनरेट करने वाला IL यह नहीं जान सकता है कि टाइप वैल्यू टाइप है या रेफरेंस (यह जेनेरिक हो सकता है) चाहे वह कॉलविट जनरेट करने वाला हो। JITTER को पता होगा कि क्या प्रकार एक मूल्य प्रकार है, और क्या यह ToString को ओवरराइड करता है, इसलिए यह बॉक्सिंग करने के लिए कॉल-साइट कोड उत्पन्न कर सकता है; वैकल्पिक रूप से, यह हो सकता हर struct कि हावी नहीं होता के लिए स्वत: जनरेट ToStringएक mehtod public override void ToString() { return base.ToString(); }और ...
supercat

... उस पद्धति के भीतर मुक्केबाजी होती है। चूंकि यह विधि बहुत ही कम होगी, इसलिए इसे लाइन में रखा जा सकता है। बाद के दृष्टिकोण के साथ चीजों को ToString()करने से किसी भी अन्य की तरह परावर्तन के माध्यम से एक संरचना की विधि को एक्सेस करने की अनुमति मिलती है और एक स्थिर प्रतिनिधि बनाने के लिए उपयोग किया जाता है जो संरचना को एक refपैरामीटर के रूप में लेता है [ऐसी चीज गैर-विरासत वाले संरचनात्मक तरीकों के साथ काम करती है], लेकिन मैं बस एक ऐसा प्रतिनिधि बनाने की कोशिश की और यह काम नहीं किया। क्या किसी संरचना की ToString()विधि के लिए एक स्थिर प्रतिनिधि बनाना संभव है , और यदि ऐसा है तो पैरामीटर प्रकार क्या होना चाहिए?
सुपरकैट

लिंक टूट गए हैं।
18

5

गैर-आभासी GetType () विधि प्रकार पर कॉल करना:

struct S { };
S s = new S();
s.GetType();

2
GetTypeबॉक्सिंग की आवश्यकता नहीं है क्योंकि यह गैर-आभासी है, लेकिन क्योंकि मूल्य-प्रकार के भंडारण स्थान, ढेर वस्तुओं के विपरीत, "छिपा हुआ" फ़ील्ड नहीं है जो GetType()उनके प्रकार की पहचान करने के लिए उपयोग कर सकते हैं।
सुपरकैट

@ सपरकट हमम। 1. संकलक द्वारा उपयोग किए गए बॉक्सिंग और रनटाइम द्वारा उपयोग किए गए छिपे हुए क्षेत्र। हो सकता है कि कंपाइलर बॉक्सिंग जोड़ दें क्योंकि यह रनटाइम के बारे में जानता है। 2. जब हम एनम वैल्यू पर नॉन-वर्चुअल टूस्ट्रिंग (स्ट्रिंग) कहते हैं तो इसके लिए भी बॉक्सिंग की आवश्यकता होती है और मुझे विश्वास नहीं होता कि कंपाइलर इसे जोड़ते हैं क्योंकि यह Enum.ToString (स्ट्रिंग) कार्यान्वयन विवरण के बारे में जानता है। । इस प्रकार, मुझे लगता है, मैं कह सकता हूं कि बॉक्सिंग हमेशा तब होती है जब "बेस वैल्यू टाइप" पर गैर-आभासी विधि कहा जाता है।
वायाचेस्लाव इवानोव

मैंने स्वयं के Enumकिसी भी गैर-आभासी तरीके पर विचार नहीं किया था , हालांकि एक ToString()विधि के लिए एक Enumप्रकार की जानकारी तक पहुंच की आवश्यकता होगी। मुझे आश्चर्य है कि Object, ValueTypeया Enumकोई गैर-आभासी तरीके हैं जो बिना किसी प्रकार की जानकारी के अपना काम कर सकते हैं।
सुपरकैट

3

Motti के उत्तर में उल्लेख किया गया है, कोड नमूने के साथ केवल चित्रण:

पैरामीटर शामिल थे

public void Bla(object obj)
{

}

Bla(valueType)

public void Bla(IBla i) //where IBla is interface
{

}

Bla(valueType)

लेकिन यह सुरक्षित है:

public void Bla<T>(T obj) where T : IBla
{

}

Bla(valueType)

वापसी प्रकार

public object Bla()
{
    return 1;
}

public IBla Bla() //IBla is an interface that 1 inherits
{
    return 1;
}

अशक्त टी के खिलाफ जाँच करना

public void Bla<T>(T obj)
{
    if (obj == null) //boxes.
}

गतिशील का उपयोग

dynamic x = 42; (boxes)

और एक

enumValue.HasFlag


0
  • गैर-जेनेरिक संग्रह System.Collectionsजैसे कि ArrayListया का उपयोग करना HashTable

दी ये आपके पहले मामले के विशिष्ट उदाहरण हैं, लेकिन वे छिपे हुए गोच हो सकते हैं। यह अद्भुत कोड की मात्रा है जो मैं अभी भी आज भर में आया हूं जो इन के बजाय List<T>और का उपयोग करता है Dictionary<TKey,TValue>


0

ArrayList में किसी भी मूल्य प्रकार के मूल्य को जोड़ना मुक्केबाजी का कारण बनता है:

ArrayList items = ...
numbers.Add(1); // boxing to object
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.