2010-04-24 4 views
10

संपादित करें: मुझे अच्छी तरह से पता है कि यह मूल्य प्रकारों के साथ बहुत अच्छी तरह से काम करता है, मेरा विशिष्ट प्रश्न संदर्भ प्रकारों के लिए इसका उपयोग करने के बारे में है।स्पष्ट संरचना में एक दूसरे के साथ कई सीएलआर संदर्भ फ़ील्ड ओवरलेइंग?

संपादित 2: मुझे यह भी पता है कि आप एक संरचना में संदर्भ प्रकार और मूल्य प्रकारों को ओवरले नहीं कर सकते हैं, यह सिर्फ एक दूसरे के साथ कई संदर्भ प्रकार फ़ील्ड ओवरले करने के मामले में है।

मैं चारों ओर नेट/सी # में structs को संवारता किया गया है, और मैं बस पता चला आप यह कर सकते हैं कि: एक struct का उपयोग करके

using System; 
using System.Runtime.InteropServices; 

namespace ConsoleApplication1 { 

    class Foo { } 
    class Bar { } 

    [StructLayout(LayoutKind.Explicit)] 
    struct Overlaid { 
     [FieldOffset(0)] public object AsObject; 
     [FieldOffset(0)] public Foo AsFoo; 
     [FieldOffset(0)] public Bar AsBar; 
    } 

    class Program { 
     static void Main(string[] args) { 
      var overlaid = new Overlaid(); 
      overlaid.AsObject = new Bar(); 
      Console.WriteLine(overlaid.AsBar); 

      overlaid.AsObject = new Foo(); 
      Console.WriteLine(overlaid.AsFoo); 
      Console.ReadLine(); 
     } 
    } 
} 

मूल रूप से रनटाइम के दौरान गतिशील कास्टिंग क्या करने वाले को धोखा देने कि एक स्पष्ट फ़ील्ड लेआउट है और फिर ऑब्जेक्ट को सही प्रकार के रूप में एक्सेस कर रहा है।

अब मेरा सवाल है: क्या इससे सीएलआर के अंदर मेमोरी लीक हो सकती है, या कोई अन्य अपरिभाषित व्यवहार हो सकता है? या यह एक पूरी तरह से समर्थित सम्मेलन है जो किसी भी मुद्दे के बिना प्रयोग योग्य है?

मुझे पता है कि यह सीएलआर के गहरे कोनों में से एक है, और यह तकनीक बहुत कम विशिष्ट मामलों में केवल एक व्यवहार्य विकल्प है।

उत्तर

2

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

struct Overlaid { // could also be a class for reference-type semantics 
    private object asObject; 
    public object AsObject {get {return asObject;} set {asObject = value;} } 
    public Foo AsFoo { get {return asObject as Foo;} set {asObject = value;} } 
    public Bar AsBar { get {return asObject as Bar;} set {asObject = value;} } 
} 

फटे संदर्भ आदि का कोई जोखिम, और अभी भी केवल एक ही क्षेत्र:

यह सुरक्षित होगा। यह किसी भी जोखिम भरा कोड, आदि विशेष रूप से शामिल नहीं है, यह की तरह कुछ मूर्ख जोखिम नहीं करता है:

[FieldOffset(0)] 
    public object AsObject; 
    [FieldOffset(0)] 
    public Foo AsFoo; 
    [FieldOffset(1)] 
    public Bar AsBar; // kaboom!!!! 

एक और मुद्दा यह है कि आप केवल जब तक आप सीपीयू मोड गारंटी ले सकते हैं एक भी क्षेत्र इस तरह का समर्थन कर सकते है ; ऑफ़सेट 0 आसान है, लेकिन यदि आपको एकाधिक फ़ील्ड की आवश्यकता है और x86 और x64 का समर्थन करने की आवश्यकता है तो यह अधिक कठिन हो जाता है।

+1

वास्तव में मेरे प्रश्न का उत्तर नहीं दिया। मैं जानना चाहता था कि क्या मैंने पूछा (और _exactly_ जो मैंने पूछा) करना संभव था। एक ही समस्या का कोई अन्य समाधान नहीं है (क्योंकि मेरा उदाहरण यहां सरलीकृत है, वास्तविक समस्या संदर्भ प्रकार का उपयोग नहीं कर सकती है)। – thr

+1

डाउनवोट की व्याख्या करने की देखभाल? यह एक ** गंभीरता से ** जोखिम भरा दृष्टिकोण है; बस कुछ संक्षिप्त कर्सर परीक्षण 'System.SystemException' जैसी चीजें दिखाते हैं - जो ** ** ** ऐसा नहीं लगता है जो आप पेश करना चाहते हैं! एक ** जोखिम ** के रूप में भी। (संदेश विवरण जैसे "" ऑब्जेक्ट इंस्टेंस पर विधि नहीं मिल सका। ") –

+0

@thr - फिर" वर्ग "को" स्ट्रक्चर "में बदलें। यह पोस्ट का महत्वपूर्ण हिस्सा नहीं था; यहां, मैं इसे बदल दूंगा आप ... –

-1

मुझे इसके साथ किसी भी मुद्दे से अवगत नहीं है। इसके अलावा, मुझे संदेह है कि माइक्रोसॉफ्ट इस उपयोग की अनुमति देगा अगर यह एक गैर-स्पष्ट तरीके से खतरनाक था।

+0

मेरी धारणा भी कौन सा है, लेकिन यह सीएलआर के बहुत ही अंधेरे कोनों में से एक की तरह लगता है और मैं चाहता हूं कि यह किसी ऐसे व्यक्ति द्वारा आश्वासन दिया जाए जो उस पर 100% है। – thr

2

यदि आप इस प्रकार को असुरक्षित तरीके से संरेखित करते हैं, तो रनटाइम के साथ संकलन करते समय लोड पर TypeLoadException फेंक देगा। तो मुझे लगता है कि आप सुरक्षित हैं।

मुझे अनुमान है - क्योंकि आप StructLayout का उपयोग कर सकते हैं और /unsafe झंडे के बिना अपना कोड संकलित कर सकते हैं - यह सीएलआर की एक विशेषता है। आपको केवल स्ट्रक्चरआउट विशेषता की आवश्यकता है क्योंकि सी # के इस तरह के प्रकार घोषित करने का कोई प्रत्यक्ष माध्यम नहीं है।

this page पर एक नज़र डालें, जिसमें सी # structs आईएल में अनुवाद करने के कुछ तरीके बताते हैं, आप देखेंगे कि आईएल/सीएलआर में अंतर्निहित कई मेमोरी लेआउट समर्थन हैं।

+0

मैं जो भी मान रहा हूं, मैं बस इसे किसी ऐसे व्यक्ति द्वारा पुष्टि करना चाहता हूं जो वास्तव में सीएलआर को जानता है कि यह किसी भी तरह से, मुझे स्मृति रिसाव या कुछ अन्य अनिश्चित व्यवहार बनाने का कारण बन सकता है। – thr

3

ठीक है, आपको एक लूप छेद मिला, सीएलआर इसे अनुमति देता है क्योंकि सभी ओवरलैप्ड फ़ील्ड ऑब्जेक्ट्स हैं।कुछ भी है कि एक वस्तु संदर्भ सीधे एक TypeLoadException साथ अस्वीकार कर दिया जाता है के साथ गड़बड़ करने के लिए आप की अनुमति होगी:

[StructLayout(LayoutKind.Explicit)] 
    struct Overlaid { 
    [FieldOffset(0)] 
    public object AsObject; 
    [FieldOffset(0)] 
    public IntPtr AsPointer; 
    } 

लेकिन तुम कक्षाएं क्षेत्रों देकर यह दोहन कर सकते हैं। जब तक आप केवल फ़ील्ड मानों को पढ़ रहे हों, तब तक वास्तव में कुछ भी बुरा नहीं होता है, उदाहरण के लिए आप ट्रैकिंग हैंडल का मूल्य प्राप्त कर सकते हैं।

उन फ़ील्ड को लिखना हालांकि निष्पादन EngineException की ओर जाता है। मुझे लगता है कि अगर आप एक ट्रैकिंग हैंडल के मूल्य का सही अनुमान लगा सकते हैं तो यह एक शोषण है। हालांकि व्यावहारिक उपयोग शून्य के करीब पर्याप्त है।

+0

यदि मैं आपको सही ढंग से समझता हूं: जब तक सभी ओवरलैपिंग फ़ील्ड ऑब्जेक्ट्स होते हैं, तो सही प्रकार (मूल रूप से 'AsObject' फ़ील्ड को असाइन करने और फिर' AsFoo'/'Asbar से पढ़ने के लिए उन्हें पढ़ने और लिखने के लिए सुरक्षित है। 'प्रकार के आधार पर क्षेत्र)? अगर मैं 'असबार' से 'फू' पढ़ने की कोशिश करता हूं तो यह निश्चित रूप से टूट जाएगा। यह मुझे किसी भी तरह से कोई स्मृति रिसाव आदि नहीं दे सकता है? – thr

+0

@thr: नहीं, कचरा कलेक्टर को इसके साथ कोई समस्या नहीं होगी। –

+0

@ हंसपैसेंट ओवरलेड सरणी का एक दिलचस्प विशेष मामला है। आप बाइट्स और स्याही की सरणी सरणी ओवरले कर सकते हैं। फिर आप बाइट [] फ़ील्ड में एन-एलिमेंट बाइट सरणी असाइन करते हैं और सीएलआर सोचता है कि आपके पास int [] फ़ील्ड में एन-एलिमेंट int सरणी है। यह आपको निर्दिष्ट स्मृति के बाहर लिखने की अनुमति देता है। कभी-कभी यह ऐप को दुर्घटनाग्रस्त करता है। –

1

चूंकि कचरा कलेक्टर अनियंत्रित है और केवल ऑब्जेक्ट संदर्भों और सादे बिट्स के बीच अंतर करता है, ओवरलैपिंग संदर्भ इसे भ्रमित नहीं करेंगे। हालांकि, जबकि एक ऑब्जेक्ट संदर्भ पूरी तरह से दूसरे को ओवरलैप कर सकता है, यह अविश्वसनीय है, उर्फ ​​असुरक्षित (ईसीएमए -335 मानक, पृष्ठ 180, II.10.7 इंस्टेंस लेआउट को नियंत्रित करना)।

using System.Runtime.InteropServices; 

class Bar 
{ 
    public virtual void func() { } 
} 

[StructLayout(LayoutKind.Explicit)] 
struct Overlaid 
{ 
    [FieldOffset(0)] 
    public object foo; 

    [FieldOffset(0)] 
    public Bar bar; 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var overlaid = new Overlaid(); 
     overlaid.foo = new object(); 
     overlaid.bar.func(); 
    } 
} 

यहाँ समारोह कॉल वस्तु वर्ग की आभासी तालिका के अंतिम तत्व के बाद एक से एक समारोह सूचक लोड करता है: यह एक प्रोग्राम है जो इस unverifiability कारनामे horrendously दुर्घटना के निर्माण के लिए आसान है। this article के अनुसार vtbl के बाद एक हैंडल टेबल है। इसे एक फ़ंक्शन पॉइंटर के रूप में समझना एक सिस्टम की ओर जाता है। एक्सेस अपॉलेशन अपवाद।

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