2012-02-15 18 views
17

यह मेरा कोड में से कुछ का एक सरलीकृत संस्करण है:साइकिल जो मौजूद नहीं है

public struct info 
{ 
    public float a, b; 
    public info? c; 

    public info(float a, float b, info? c = null) 
    { 
     this.a = a; 
     this.b = b; 
     this.c = c; 
    } 
} 

समस्या त्रुटि Struct member 'info' causes a cycle in the struct layout. मैं मान प्रकार व्यवहार की तरह struct के बाद कर रहा हूँ है। मैं इसे कक्षा और क्लोन सदस्य समारोह का उपयोग करके अनुकरण कर सकता हूं, लेकिन मुझे नहीं लगता कि मुझे इसकी आवश्यकता क्यों है।

यह त्रुटि कैसे सच है? रिकर्सन शायद कुछ समान परिस्थितियों में निर्माण का कारण बन सकता है, लेकिन मैं इस मामले में ऐसा किसी भी तरीके से नहीं सोच सकता। नीचे उदाहरण हैं जो प्रोग्राम को संकलित करने के लिए ठीक होना चाहिए।

new info(1, 2); 
new info(1, 2, null); 
new info(1, 2, new info(3, 4)); 

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

समाधान मैं का इस्तेमाल किया "जानकारी" एक वर्ग के बजाय एक struct और यह एक प्रति है कि मैं जब यह गुजर इस्तेमाल किया लौटे करने के लिए एक सदस्य समारोह दे रही है बनाने के लिए किया गया था। प्रभाव में एक संरचना के रूप में एक वर्ग के साथ समान व्यवहार अनुकरण।

मैंने उत्तर की तलाश करते समय निम्न प्रश्न भी बनाया।

Value type class definition in C#?

+0

मेरा अनुमान है कि आपको कम से कम एक कन्स्ट्रक्टर होना चाहिए जो पैरामीटर के रूप में 'जानकारी' नहीं लेता है? आप एक डिफ़ॉल्ट तर्क का उपयोग कर रहे हैं, लेकिन शायद सी # इसे पसंद नहीं है। यदि आप दो रचनाकार बनाते हैं तो क्या होता है? –

+2

बस इसे एक वर्ग बनाएं; यह संरचना डेटा –

+0

'जानकारी नहीं है?' 'सूचक 'के लिए * सूचक नहीं है, यह एक प्रति है। यदि आपको वास्तव में इसकी आवश्यकता है (आपको नहीं करना चाहिए), अपना खुद का नामुमकिन प्रकार क्यों न बनाएं जो 'वर्ग' है? आप 'Nullable ' से 'YourNullable ' में परिवर्तित करने के लिए निहित ऑपरेटर भी हो सकते हैं। निस्संदेह, इसका मतलब है 'योर नेलबल' का * बोटलोड *, आपकी कक्षा को 'स्ट्रक्चर' होने से शायद किसी भी बोनस (यदि कोई था) को हटा दें :) सी # 'स्ट्रक्चर सी 'स्ट्रक्चर' नहीं है रों। सभी गणनाओं पर – Luaan

उत्तर

26

ऐसी कोई संरचना नहीं है जिसमें एक सदस्य के रूप में स्वयं शामिल हो। ऐसा इसलिए है क्योंकि एक संरचना में निश्चित आकार है, और यह कम से कम अपने प्रत्येक सदस्यों के आकार के योग के रूप में बड़ा होना चाहिए। आपके प्रकार के दो फ्लोट्स के लिए 8 बाइट्स होना चाहिए, कम से कम एक बाइट यह दिखाने के लिए कि info शून्य है, साथ ही info का आकार भी है। यह निम्नलिखित असमानता देता है:

size of info >= 4 + 4 + 1 + size of info 

यह स्पष्ट रूप से असंभव है क्योंकि इसे आपके प्रकार की असीम रूप से बड़ी आवश्यकता होगी।

आपको संदर्भ प्रकार (यानी कक्षा) का उपयोग करना होगा। String कक्षा के समान, आप अपनी कक्षा को अपरिवर्तनीय बना सकते हैं और Equals और GetHashCode को मूल्य-समान व्यवहार देने के लिए ओवरराइड कर सकते हैं।

+0

+1 अच्छी सलाह। आप टाइप ऑब्जेक्ट के सी सदस्य को भी बना सकते हैं, इसे बॉक्सिंग करने के लिए मजबूर कर सकते हैं (कन्स्ट्रक्टर अभी भी एक जानकारी ले सकता है?)। एक बदसूरत बिट बिट – MattDavey

+0

यह वास्तव में मेरे लिए काम करता है। 'सार्वजनिक जानकारी? सी; 'कोई त्रुटि नहीं देता है, यह संरचना और संदर्भ आकार के संदर्भ की तरह व्यवहार करता है निर्धारणीय है। –

10

कारण है कि यह एक चक्र है कि Nullable<T> अपने आप में एक struct है। क्योंकि यह info पर वापस संदर्भित करता है आपके पास लेआउट में एक चक्र है (info में Nullable<info> का क्षेत्र है और इसमें info का क्षेत्र है)।

public info? c; 

इस के बाद से एक struct है, सी # भीतरी info/s लेआउट पता करने के लिए इससे पहले कि यह बाहरी info उत्पादन कर सकता है की जरूरत है: यह अनिवार्य रूप से निम्नलिखित

public struct MyNullable<T> { 
    public T value; 
    public bool hasValue; 
} 

struct info { 
    public float a, b; 
    public MyNullable<info> next; 
} 
4

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

नोट: info? cNullable<info> के लिए एक शॉर्टेंड है जो स्वयं struct है।

2

वहाँ किसी भी तरह से चर आकार वस्तुओं की परिवर्तनशील मूल्य अर्थ विज्ञान को प्राप्त करने के लिए नहीं है (शब्दार्थ, मुझे लगता है कि तुम क्या कर रहे हैं के बाद MyInfo1 = MyInfo2 एक नया लिंक्ड सूची जो एक MyInfo2 द्वारा शुरू से अलग है उत्पन्न करने के लिए है)। कोई को(जो हमेशा या तो शून्य या अन्य एकल तत्व तत्व के साथ पॉप्युलेट किया जाएगा) के साथ प्रतिस्थापित कर सकता है, या धारक वर्ग के साथ जो info के उदाहरण को लपेटता है, लेकिन अर्थशास्त्र शायद आपके बाद के बाद नहीं होगा । MyInfo1 = MyInfo2 के बाद, MyInfo1.a में परिवर्तन MyInfo2.a को प्रभावित नहीं करेंगे, न ही MyInfo1.c में MyInfo2.c को प्रभावित करेगा, लेकिन MyInfo1.c[0].a में परिवर्तन MyInfo2.c[0].a को प्रभावित करेगा।

यह अच्छा होगा अगर .NET के भविष्य के संस्करण में "मान संदर्भ" की कुछ अवधारणा हो सकती है, ताकि एक संरचना की प्रतिलिपि न केवल अपने सभी क्षेत्रों की प्रतिलिपि बना सके। इस तथ्य के लिए कुछ मूल्य है कि .NET सी ++ प्रतिलिपि बनाने वालों की सभी जटिलताओं का समर्थन नहीं करता है, लेकिन 'संरचना' प्रकार के भंडारण स्थानों को पहचानने के लिए मूल्य भी होगा जो भंडारण स्थान से जुड़ा होगा इसकी सामग्री

यह देखते हुए कि नेट वर्तमान में ऐसी किसी भी अवधारणा का समर्थन नहीं करता है, हालांकि, यदि आप info उत्परिवर्तनीय होने के लिए चाहते हैं, तो आपको या तो म्यूटेबल संदर्भ अर्थशास्त्र (सुरक्षात्मक क्लोनिंग सहित) या अजीब और निराशाजनक के साथ रखना होगा संरचना-वर्ग-संकर अर्थशास्त्र। एक सुझाव यह है, तो प्रदर्शन चिंता का विषय वंश MutableInfo और ImmutableInfo साथ एक सार InfoBase वर्ग के लिए होगा मैं, होता है और निम्नलिखित के सदस्यों के साथ:

  1. AsNewFullyMutable - सार्वजनिक उदाहरण - रिटर्न एक नया MutableInfo वस्तु, मूल से कॉपी किए गए डेटा के साथ, किसी नेस्टेड संदर्भों पर AsNewFullyMutable पर कॉल करना।

  2. AsNewMutable - सार्वजनिक उदाहरण - एक नया MutableInfo वस्तु, मूल से प्रतिलिपित डेटा से रिटर्न, किसी भी नेस्टेड संदर्भों पर AsImmutable बुला।

  3. AsNewImmutable - संरक्षित उदाहरण - एक नया ImmutableInfo वस्तु देता है, orignal से प्रतिलिपित डेटा से, किसी भी नेस्टेड संदर्भों पर बुला AsImmutable (AsNewImmutable नहीं)।

  4. AsImmutable - सार्वजनिक वर्चुअल - ImmutableInfo के लिए, स्वयं लौटें; MutableInfo के लिए, AsNewImmutable पर कॉल करें।

  5. AsMutable - सार्वजनिक वर्चुअल - MutableInfo के लिए, स्वयं लौटें; ImmutableInfo के लिए, AsNewMutable पर कॉल करें।

जब एक वस्तु क्लोनिंग, पर कि क्या एक उम्मीद है कि वस्तु या उसके वंश फिर से क्लोन किया जाएगा इससे पहले कि यह उत्परिवर्तित किया जा सकता था निर्भर करता है, एक या तो AsImmutable, AsNewFullyMutable, या AsNewMutable कहेंगे। परिदृश्यों में जहां कोई ऑब्जेक्ट को बार-बार रक्षात्मक रूप से क्लोन करने की अपेक्षा करता है, ऑब्जेक्ट को एक अपरिवर्तनीय उदाहरण से प्रतिस्थापित किया जाएगा, तब तक इसे तब तक क्लोन नहीं किया जाना चाहिए जब तक कि इसे बदलने की इच्छा न हो।