2012-11-08 12 views
8

पर एक पॉइंटर का आकार प्राप्त करने, आकार प्राप्त करने या घोषित करने का पता नहीं लगा सकता है, मैंने शोध का एक उचित हिस्सा किया है, लेकिन अब मुझे अटक गया है कि मुझे अभी भी यह त्रुटि क्यों मिल रही है। मैं निम्न विशेषताओं वाला एक struct है:किसी प्रबंधित प्रकार

struct Account 
{ 
    //private attributes 
    private double mBalance; 
    private int mAccountNumber; 
    private string mName; 
    private string mDateCreated; 
} 

और निम्न करने के लिए कोशिश कर रहा हूँ:

class BankManager 
{ 
    //private attributes 
    private unsafe Account *mAccounts; 
    private unsafe bool *mAccountsAvailable; 
    private int mNumberAccounts; 
} 

यहां तक ​​कि एक struct करने के लिए मेरी कक्षा खाता मोड़, कक्षा में विशेषताओं के लिए "असुरक्षित" उपयोग करने के बाद BankManager, और संकलक यह असुरक्षित कोड का उपयोग कर सकते कह (गुण में -> बिल्ड), मैं अभी भी इस त्रुटि

*mAccounts 

पर क्यों के रूप में हो रही है कोई भी विचार? मुझे पूरा यकीन है कि संरचना में उपयोग किए जा रहे सभी प्रकार के सी # में पॉइंटर्स होने के लिए कानूनी हैं। अग्रिम में धन्यवाद!

+1

आप पॉइंटर्स का उपयोग क्यों करना चाहते हैं? ऐसा लगता है कि 'बैंकमैनगर' के पास 'खाता' का 'संग्रह' होगा। – Xint0

+0

इससे मदद मिल सकती है: http://stackoverflow.com/questions/2559384/cannot-take-the-address-of-get-the-size-of-or-declare-a-pointer-to-a-managed-t – sellmeadog

उत्तर

20

खाता वर्ग में तार इस समस्या का कारण बनते हैं। समझने के लिए, आपको समझने की जरूरत है कि कचरा कलेक्टर कैसे काम करता है। यह वस्तुओं के संदर्भों को ट्रैक करके कचरा खोजता है। एमएनएएम और एमडीएटक्रेटेड ऐसे संदर्भ हैं। MBalance और mAccountNumber नहीं हैं, वे फ़ील्ड मूल्य प्रकार हैं। और, सबसे महत्वपूर्ण बात यह है कि BankManager.mAccounts फ़ील्ड नहीं है, यह एक सूचक है।

तो कंपाइलर आगे बता सकता है कि कचरा कलेक्टर कभी भी स्ट्रिंग संदर्भ देखने में सक्षम नहीं होगा। क्योंकि ऐसा करने का एकमात्र तरीका mAccount फ़ील्ड से जाना है और इसका संदर्भ नहीं है।

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

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

+0

धन्यवाद! – SantasNotReal

0

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

1

private unsafe fixed char mName[126];
स्ट्रिंग प्रबंधित प्रकार हैं, और इसलिए गैर-निर्धारित सरणी हैं।

+0

ठीक है, मैं समझता हूं कि तारों को प्रबंधित किया जाता है, लेकिन वर्णों की अनुमति है। तो जब मैं उपर्युक्त करता हूं, तो मुझे मिलता है: सार्वजनिक चार नाम { {वापसी mName; } सेट {mName = value; } } त्रुटि के साथ "आप निश्चित आकार में निहित निश्चित आकार बफर का उपयोग नहीं कर सकते हैं। निश्चित कथन का उपयोग करने का प्रयास करें।" – SantasNotReal

3

स्ट्रिंग्स .NET में संदर्भ प्रकार हैं और संरचना पॉइंटर्स के लिए गैर-ब्लिटेबल हैं। आप जो करना चाहते हैं उसके मूल्य प्रकारों की सूची के लिए Blittable and Non-Blittable Types देखें।

जब तक आपके पास विशेष व्यावसायिक आवश्यकताएं न हों, आपको रखरखाव और सामान्य स्वच्छता के लिए प्रबंधित स्मृति के साथ रहना चाहिए।

+0

यह उत्तर स्वीकार्य उत्तर की तुलना में मेरे लिए अधिक फायदेमंद था क्योंकि यह बड़े डिजाइन मुद्दे का वर्णन करता है। मेरी विशेष समस्या एक int [] सरणी गुण वाली संरचना से संबंधित थी, जो कि विचित्र नहीं है, और परिणामस्वरूप OP के समान त्रुटि होती है। विस्तृत जानकारी के लिए –

-1

प्रबंधित डेटा एक निश्चित स्थान पर नहीं रहता है, क्योंकि प्रतिलिपि संग्रहकर्ता चीजों को चारों ओर स्थानांतरित कर सकता है। यह प्रबंधित बॉक्स किए गए मान प्रकारों के समान ही सच है। प्रबंधित अनबॉक्स किए गए मान-प्रकार केवल स्टैक या अन्य ऑब्जेक्ट्स के अंदर ही रह सकते हैं। यदि वे ढेर में हैं तो उनके पास केवल निश्चित स्थान हैं।

एक ढेर-आवंटित संरचना बनाने के लिए जिसमें एक निश्चित स्थान है जिसमें से आप एक सूचक ले सकते हैं जो वैध रहेगा, आपको इसे अप्रबंधित मेमोरी में आवंटित करना होगा। हालांकि, एक बार जब आप इसे अप्रबंधित स्मृति में आवंटित कर लेते हैं, तो आप अब प्रबंधित पॉइंटर्स नहीं डाल सकते हैं (उर्फ, आप स्ट्रिंग का उपयोग नहीं कर सकते हैं), क्योंकि कचरा कलेक्टर उन पॉइंटर्स के बारे में नहीं जानता है, इसलिए यह अपडेट नहीं होगा जब यह compaction के दौरान चारों ओर प्रबंधित वस्तुओं को स्थानांतरित करता है।

[StructLayout(LayoutKind.Sequential, Pack=1)] 
public unsafe struct Account { 
    public int a; 
    public char* mName; 
} 
public class BankManager { 
    private unsafe Account* mAccounts; 
    public unsafe int GetA() { 
     return mAccounts->a; 
    } 
    public unsafe BankManager() { 
     mAccounts = (Account*)Marshal.AllocHGlobal(sizeof(Account)); 
    } 
    unsafe ~BankManager() { 
     if (mAccounts != null) { 
      Marshal.FreeHGlobal((IntPtr)mAccounts); 
      mAccounts = null; 
     } 
    } 
} 

यहाँ हम अप्रबंधित स्मृति में struct आवंटित:

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

मैंने संरचना को इस कोड के व्यवहार को इसके सी-समकक्ष के करीब बनाने के लिए क्रमिक लेआउट पैक किया है, क्योंकि ऊपर की तरह कोड सामान्य रूप से केवल देशी सी DllImport एंट्रीपॉइंट के साथ इंटरऑप करते समय उपयोग किया जाएगा जो किसी विशेष संरचना की अपेक्षा करता है लेआउट।

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