2013-04-04 6 views
8

सी #+ में सी ++ के वैरिएन्ट डेटाटाइप के बराबर क्या है?सी ++ में सी ++ में वैरिएन्ट डेटाटाइप सी #

मेरे पास सी ++ में कोड है जो वैरिएंट डेटाटाइप का उपयोग करता है। मैं उस कोड को सी # में कैसे परिवर्तित कर सकता हूं?

+0

क्या आपको सी ++ कोड के साथ इंटरऑप करने या बस कोड बदलने की आवश्यकता है? – Botz3000

+3

प्रत्यक्ष समकक्ष 'ऑब्जेक्ट' प्रकार और 'object.GetType() 'के रूप में" संस्करण में क्या है? "के रूप में है जानकारी, लेकिन यह वास्तव में खराब सी # कोड के लिए बना देगा। संदर्भ महत्वपूर्ण है। – Jon

+0

यदि आप सी # 4.0 का उपयोग कर रहे हैं, तो आप 'गतिशील' डेटाटाइप का उपयोग कर सकते हैं, लेकिन @ जोन ने कहा, यह खराब सी # कोड के लिए बना देगा, क्योंकि आप टाइप सॉफ्टी और संकलन-समय की जांच को बाधित करते हैं। –

उत्तर

1

यह एक मुश्किल सवाल है।

सी # 4 से, आप गतिशील का उपयोग यह इंगित करने के लिए कर सकते हैं कि प्रकार रन-टाइम पर जाना जाता है।

मेरी व्यक्तिगत समझ से, हालांकि, सी ++ को संकलन समय पर ज्ञात प्रकार की आवश्यकता होती है। इस प्रकार आप object का उपयोग करने पर विचार कर सकते हैं, लेकिन सी # में object एक मौजूदा प्रकार है।

संस्करण के बहु प्रकार की अवधारणा, एकल मान (उर्फ बहुरूपता) के लिए, आप सिर्फ अपने वर्गों और इंटरफेस को परिभाषित सी # में एक इसी प्रकार खोजने की जरूरत नहीं है,। आप हमेशा ऑब्जेक्ट को इसके इंटरफ़ेस के रूप में संदर्भित कर सकते हैं जो कक्षा लागू करता है।

यदि आप कोड को पोर्ट कर रहे हैं, और एक वाक्यविन्यास को समझने के लिए जिसे आप आसानी से एलएचएस में उपयोग कर सकते हैं और इस प्रकार के विचार के लिए संकलन समय पर जाना जाता है, तो var का उपयोग करें।

7

ठीक है, वास्तव में सी ++ में दो संस्करण हैं: boost :: variant और COM संस्करण। समाधान एक ही विचार को कम या कम करता है, लेकिन पूर्व अधिक जटिल है। मुझे उम्मीद है कि आप बाद वाले का उपयोग करना चाहते हैं।

मुझे पहले यह कहकर शुरू करना है कि यह ऐसा कुछ है जिसे आप संभवतः उपयोग नहीं करना चाहिए। जिसके अनुसार, यह कैसे आप इसे :-)

प्रकार करते हैं और इंटरॉप

प्रकार कभी कभी के इंटरॉप में उपयोग किया जाता है, तो आप बाइट प्रतिनिधित्व की जरूरत है एक ही हो रहा है।

यदि आप इंटरऑप से निपट रहे हैं, तो एमएसडीएन पर VariantWrapper कक्षा को जांचना सुनिश्चित करें और इसे इस तरह काम करें।

प्रकार और पोर्टिंग विचार

प्रकार ज्यादातर एपीआई में किया जाता है, और आमतौर पर इस तरह:

void Foo(SomeEnum operation, Variant data); 

कारण यह सी में इस तरह किया है ++ है, क्योंकि वहाँ कोई आधार object वर्ग है और इसलिए आपको इस तरह कुछ चाहिए।

void Foo(SomeEnum operation, object data); 

हालांकि, क्योंकि वे संकलन समय पर हल कर रहे हैं और आप को बचा सकता है, तो क्या आप फिर भी पोर्टिंग रहे हैं, आप भी गंभीरता से इन दोनों पर विचार करना चाहते: बंदरगाह को यह सबसे आसान तरीका है करने के लिए हस्ताक्षर बदलने के लिए है बड़े 'स्विच' है कि आमतौर पर विधि Foo में इस प्रकार है:

void SomeOperation(int data); 
void SomeOperation(float data); 
// etc 

प्रकार और बाइट स्थिरता

दुर्लभ मामलों में आप खुद को बाइट्स में हेरफेर करने की जरूरत है।

अनिवार्य रूप से संस्करण एक मान प्रकार (संरचना) में लिपटे मूल्य प्रकारों का एक बड़ा संघ है। सी ++ में, आप ढेर पर एक मान प्रकार आवंटित कर सकते हैं क्योंकि एक संरचना एक वर्ग (अच्छी तरह से क्रमबद्ध) के समान होती है। मूल्य प्रकार का उपयोग कैसे किया जा रहा है, यह थोड़ा सा महत्वपूर्ण है लेकिन बाद में उस पर अधिक महत्वपूर्ण है।

संघ का मतलब है कि आप स्मृति में सभी डेटा ओवरलैप करने जा रहे हैं। ध्यान दें कि मैंने स्पष्ट रूप से उपरोक्त मान प्रकार को कैसे नोट किया है; संस्करण के लिए यह मूल रूप से यह सब कुछ है। यह हमें परीक्षण करने का एक तरीका भी देता है - अर्थात् संरचना में एक और मूल्य की जांच करके।

सी # में यह करने के लिए जिस तरह से एक मान प्रकार, जो मूल रूप से इस प्रकार काम करता है में StructLayout विशेषता का उपयोग करने के लिए है:

[StructLayout(LayoutKind.Explicit)] 
public struct Variant 
{ 
    [FieldOffset(0)] 
    public int Integer; 
    [FieldOffset(0)] 
    public float Float; 
    [FieldOffset(0)] 
    public double Double; 
    [FieldOffset(0)] 
    public byte Byte; 
    // etc 
} 

// Check if it works - shouldn't print 0. 
public class VariantTest 
{ 
    static void Main(string[] args) 
    { 
     Variant v = new Variant() { Integer = 2 }; 
     Console.WriteLine("{0}", v.Float); 

     Console.ReadLine(); 
    } 
} 

सी ++ संस्करण का भी ढेर पर संग्रहीत किया जा सकता जैसा कि मैंने पहले उल्लेख किया। यदि आप ऐसा करते हैं, तो आप शायद अभी भी स्मृति हस्ताक्षर समान होना चाहते हैं। ऐसा करने का तरीका वेरिएंट स्ट्रक्चर को बॉक्स करना है जिसे हम पहले object पर ले कर बनाते हैं।

+0

@ केनकिन वास्तव में यह मैंने दिया 4 विकल्पों में से एक है ... – atlaste

0

चलो एक कदम पीछे ले जाएं। जल्दी या बाद में, हम वैरिएंट में वास्तविक डेटा चाहते हैं। एक वैरिएंट अर्थपूर्ण डेटा के लिए सिर्फ एक धारक है। मान लीजिए कि हमने VARIANT को C# में किसी प्रकार के ऑब्जेक्ट में परिवर्तित किया था जिसमें .NET हुड के तहत संस्करण प्रकार और कुछ कच्चा बफर था (उदा। .NET स्ट्रिंग कच्चे बफर का पर्दाफाश कर सकते हैं)। उस बिंदु पर, वैरिएंट प्रकार को ऑब्जेक्ट से निर्धारित किया जाना चाहिए और कच्चे डेटा को रूपांतरित करके या संस्करण द्वारा निर्दिष्ट डेटा प्रकार में डाला जाना चाहिए, और उसके बाद एक नया ऑब्जेक्ट बनाएं। स्ट्रिंग/पूर्णांक/आदि। कच्चे डेटा से।

तो, V1 से VARIANT को पार करने के बारे में चिंता करने के बजाय, संस्करण डेटा प्रकार को देखें और इसे C++ में वास्तविक डेटा प्रकार में परिवर्तित करें और उसे C# तक पास करें।

उदाहरण के लिए, यदि VARIANT प्रकार VT_INT है, तो पूर्णांक संस्करण से मिलता है और की तरह कुछ का उपयोग कर सकते हैं:

VARIANT var; 

Int^ returnInt = gcnew Int(var.intVal); 

returnInt एक सी में एक सी ++ समारोह से एक बाहर पैरामीटर के रूप में वापस किया जा सकता ++ dll जिसे सी # से बुलाया जा सकता है। सी ++ डीएल को/clr विकल्प का उपयोग करने की आवश्यकता है।

void ThisFunctionReturnsAnInt(Runtime::InteropServices::OutAttribute Int^ % returnIntValue) 
{ 

    VARIANT var; 
    Int^ returnInt = gcnew Int(var.intVal); 
} 

अन्य डेटा प्रकार के लिए समान दृष्टिकोण का उपयोग कर सकते: - जैसे

समारोह लगेगा। यह केवल प्राकृतिक है, VT_INT का एक वैरिएंट वास्तव में एक इंट की तरह है, ऐसा नहीं है कि कुछ प्रमुख रूपांतरण चल रहा है, आप उस समय वैरिएंट से वास्तविक मूल्य ले रहे हैं जब आप इसमें रुचि रखते हैं यदि आप सी ++ से सी # तक सीधे पूर्णांक मान पास कर रहे थे। आपको अभी भी जीसीएनयू करने की ज़रूरत होगी।

1

नेट एक COM इंटरफेस, बस उपयोग VARIANT * बजाय लागू करता है।

फिर बाईपास सूचक प्राप्त करने के लिए एक IntPtr प्रकार का उपयोग करके नेट प्राप्त तरफ वास्ते।

public class ComVariant 
{ 
    [StructLayout(LayoutKind.Sequential)] 
    public struct Variant 
    { 
     public ushort vt; 
     public ushort wReserved1; 
     public ushort wReserved2; 
     public ushort wReserved3; 
     public Int32 data01; 
     public Int32 data02; 
    } 

    private Variant _variant; 

    private IntPtr _variantPtr; 

    public ComVariant(int variantPtr) : this(new IntPtr(variantPtr)) 
    { 
    } 

    public ComVariant(IntPtr variantPtr) 
    { 
     _variant = (Variant)Marshal.PtrToStructure(variantPtr, typeof(Variant)); 
     _variantPtr = variantPtr; 
    } 

    public VarEnum Vt 
    { 
     get 
     { 
      return (VarEnum)_variant.vt; 
     } 
     set 
     { 
      _variant.vt = (ushort)value; 
     } 
    } 

    public object Object 
    { 
     get 
     { 
      return Marshal.GetObjectForNativeVariant(_variantPtr); 
     } 
    } 
} 
तो

यदि आप एक COM इंटरफेस वस्तु उदाहरण के लिए एक VT_UNKNOWN इशारा तक पहुँच रहे हैं, बस

var variant = new ComVariant(variantPtr); 
var stream = variant.Object as IStream; // will not be null if type is correct 
var obj = variant.Object as IObj; // in general... 

चाल करना होगा, लेकिन ध्यान एक नव आवंटित VARIANT और करने के लिए अपने स्वामित्व देने का उपयोग नहीं करने देना .NET कार्यान्वयन इसे कहीं भी हटाए बिना ...

अधिक जटिल कोड के लिए आपthis article पढ़ सकते हैं जो स्मृति प्रबंधन के बारे में भी बात करता है।

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