2010-05-03 8 views
6

मेरे पास एक सामान्य कार्य है जो संरचना के लिए बाध्य है। मेरे इनपुट बॉक्स किए गए हैं ("ऑब्जेक्ट्स")। क्या प्रत्येक संभावित प्रकार की जांच करने से बचने के लिए रनटाइम पर मान को अनबॉक्स करना संभव है और मैन्युअल रूप से कास्ट करता है?बॉक्स किए गए मान प्रकारों का सामान्य अनबॉक्सिंग

ऊपर के उदाहरण देखें:

public struct MyStruct 
    { 
     public int Value; 
    } 

    public void Foo<T>(T test) 
     where T : struct 
    { 
     // do stuff 
    } 

    public void TestFunc() 
    { 
     object o = new MyStruct() { Value = 100 }; // o is always a value type 

     Foo(o); 
    } 

उदाहरण में, मुझे पता है कि ओ एक struct होना चाहिए (हालांकि, यह होने के लिए MyStruct ... की जरूरत नहीं है)। क्या हर संभावित संरचना प्रकार की जांच करने के लिए बॉयलरप्लेट कोड के बिना फू को कॉल करने का कोई तरीका है?

धन्यवाद।

+0

दिलचस्प सवाल। जानकारी वहां सब कुछ है लेकिन "सामान्य रूप से व्युत्पन्न" करने का एक तरीका प्रतीत नहीं होता है। अधिक निराश। किसी ने गतिशीलता का उल्लेख किया (4.5 की आवश्यकता है)। और मुझे आश्चर्य है कि कोई अभिव्यक्ति पेड़ के साथ कुछ बना सकता है। –

उत्तर

7

.NET जेनरिक इस तरह से कार्यान्वित किए जाते हैं जो मूल्य प्रकार को किसी भी मुक्केबाजी/अनबॉक्सिंग ओवरहेड के बिना सामान्य प्रकार पैरामीटर के रूप में अनुमति देता है। चूंकि आप फू को कॉल करने से पहले ऑब्जेक्ट कास्टिंग कर रहे हैं, इसलिए आप इसका लाभ नहीं उठाते हैं, वास्तव में आप जेनिक्स का भी लाभ नहीं ले रहे हैं।

जेनिक्स का उपयोग करने का पूरा बिंदु "ऑब्जेक्ट-मुहावरे" को प्रतिस्थापित करना है। मुझे लगता है कि आप यहां अवधारणा खो रहे हैं। जो भी प्रकार T होता है, यह रन-टाइम पर उपलब्ध होता है और क्योंकि आपने इसे स्ट्रक्चर प्रकार के लिए गारंटीकृत संरचना के लिए बाध्य किया है।

आपका TestFunc समस्या के बिना इस तरह लिखा जा सकता है:

public void TestFunc() 
{ 
    MyStruct o = new MyStruct() { Value = 100 }; // o is always a value type 

    Foo<MyStruct>(o); 
} 

फू को देखते हुए, यह आपके उदाहरण में इस प्रकार दिखाई देगा:

public void Foo<T>(T test) 
    where T : struct 
{ 
    T copy = test; // T == MyStruct 
} 

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

ठीक है, के बाद से ओपी ने स्पष्ट किया कि वह जेनेरिक विधि को कॉल करना चाहता है लेकिन उसे अपनी संरचना के प्रकार (यह सिर्फ वस्तु है) नहीं जानता है। सही प्रकार पैरामीटर के साथ अपनी जेनेरिक विधि को कॉल करने का सबसे आसान तरीका थोड़ा प्रतिबिंब का उपयोग करना है।

public void TestFunc() 
{ 
    object o = new DateTime(); 

    MethodInfo method = this.GetType().GetMethod("Foo"); 
    MethodInfo generic = method.MakeGenericMethod(o.GetType()); 
    generic.Invoke(this, new object[] {o}); 


} 
public void Foo<T>(T test) 
    where T : struct 
{ 
    T copy = test; // T == DateTime 
} 
+0

लेकिन अगर मुझे नहीं पता कि ओ एक MyStruct होगा? यह किसी भी संरचना या मूल्य प्रकार से हो सकता है? TestFunc केवल एक उदाहरण है, मेरे आवेदन में डेटा एक शब्दकोश <स्ट्रिंग, ऑब्जेक्ट> से आता है जहां मूल्य कुछ भी हो सकता है। हालांकि, मुझे पता है कि यह एक संरचना होना चाहिए और इसलिए मैं कंक्रीट प्रकार की जांच किए बिना फू को कॉल करना चाहता हूं। – slurmomatic

+0

लेकिन आपको ठोस प्रकार की आवश्यकता क्यों है? जेनेरिक का उपयोग करने का मुद्दा कंक्रीट प्रकार से दूर करना है। क्या आपको किसी वस्तु को ठोस प्रकार या क्या करने की आवश्यकता है? फिर आपको उदाहरण के द्वारा कास्टिंग में देखना होगा। –

+0

मुझे ठोस प्रकार की आवश्यकता नहीं है, लेकिन चूंकि मैं "संरचना" में नहीं डाल सकता, इसलिए मुझे फू () को कॉल करने के लिए ठोस प्रकार को जानने की आवश्यकता है। – slurmomatic

2

नहीं; आप object का उपयोग कर रहे हैं, जो (परिभाषा के अनुसार) एक संरचना/मान प्रकार नहीं है। आप जानबूझकर इस तरह के मूल्य को मुक्केबाजी क्यों कर रहे हैं?

+1

मेरे सभी मान एक शब्दकोश में संग्रहीत हैं, यदि मेरे पास एक शब्दकोश हो सकता है मुझे इसका उपयोग करने में खुशी होगी :) मैं अपने असली एप्लिकेशन में "जानबूझकर" मुक्केबाजी का मूल्य नहीं हूं, यह बस एक साधारण उदाहरण था। – slurmomatic

+2

@sluromatic: मैं कठिनाई देख सकता हूं, फिर। दुर्भाग्यवश, वास्तविक कंक्रीट मूल्य प्रकार को जानने के बिना आप जो करने की कोशिश कर रहे हैं, उसे करने का कोई तरीका नहीं है। –

+0

नहीं, आप थोड़ा प्रतिबिंब जादू का उपयोग कर सकते हैं (नीचे मेरा जवाब देखें)। –

0

जेनिक्स का उपयोग करने का पूरा बिंदु इस तरह की स्थितियों से बचने के लिए है।

जब आप वास्तव में एक प्रकार की संरचना के साथ जेनेरिक "बंद" करते हैं, तो आप रनटाइम प्रकार की जांच की आवश्यकता को खत्म करते हैं: यानी।

Foo<MyStruct>(MyStruct test); 

फू का आपका कार्यान्वयन, सुरक्षित रूप से मान सकते हैं कि यह एक struct के साथ काम कर रहा है।

+0

हां, लेकिन मुझे नहीं पता कि यह एक MyStruct है, मुझे केवल इतना पता है कि यह एक संरचना है। यह MyStruct2, MyStruct3, int, char, आदि हो सकता है – slurmomatic

+0

बिल्कुल, उन मामलों में आप कॉल को Foo (MyStruct2 test) Foo (MyStruct3 test) आदि के रूप में कॉल करेंगे ... मुझे पूरा यकीन नहीं है कि आप क्यों जेनिक्स का उपयोग सिर्फ अपनी मुख्य सुविधा (डिजाइन समय प्रकार पैरामीटरेशन) के आसपास काम करने के लिए करें – Pierreten

+0

ठीक है, उदाहरण। मेरे पास एक सामान्य वर्ग मान है लेकिन एक इंटरफ़ेस IValue भी है (सूची और IList की तुलना करें)। मुझे पता है कि मेरे सभी IVALues वैल्यू के कुछ ठोस संस्करण हैं। लेकिन वैल्यू के किसी भी तरीके को कॉल करने के लिए मुझे कंक्रीट प्रकार पर डालना होगा, उदा। मूल्य , मूल्य आदि – slurmomatic

0

(सीडब्ल्यू के रूप में चिह्नित है क्योंकि आप एक सामान्य एक struct की आवश्यकता होती है करने के लिए ValueType का एक उदाहरण पारित नहीं हो सकता है, लेकिन यह अन्य लोगों के इस सवाल के पार चलो के लिए उपयोगी हो सकता है)। एक object के रूप में घोषित करने के o


इसके बजाय, आप System.ValueType का एक प्रकार है, जो केवल struct मूल्यों सौंपा जा सकता है का उपयोग कर सकते हैं; आप को ValueType में स्टोर नहीं कर सकते हैं।

हालांकि, मैं ईमानदारी से यह सुनिश्चित नहीं कर रहा हूं कि यह (अन) मुक्केबाजी के मामले में कुछ भी करता है। ध्यान दें कि ECMA-334 11.1.1 कहता है:

System.ValueType स्वयं मूल्य-प्रकार नहीं है। इसके बजाय, यह एक वर्ग-प्रकार है जिसमें से सभी मूल्य-प्रकार स्वचालित रूप से व्युत्पन्न होते हैं।

+0

'वैल्यू टाइप' का कोई भी उदाहरण, विडंबनात्मक रूप से एक संदर्भ है। यह मूल्य प्रकारों तक सीमित जेनेरिक के लिए काम नहीं करेगा। –

0

मुझे पता है कि वास्तव में क्या आप archieve करने के लिए कोशिश कर रहे हैं नहीं है, लेकिन आप मूल्य Unbox के लिए एक प्रतिनिधि/लैम्ब्डा गुजारें सकता है, और struct में कुछ मूल्य का चयन आप में रुचि रखते हैं:

(अपडेट किया गया slurmomatics टिप्पणी के बाद इस कोड स्निपेट)

public void Foo<TValue>(object test, Func<object, TValue> ValueSelector) 
      where TValue : struct 
{ 
    TValue value = ValueSelector(test); 

    // do stuff with 'value' 
} 

public void TestFunc() 
{ 
    object o = new MyStruct() { Value = 100 }; 

    // Do the unboxing in the lambda. 
    // Additionally you can also select some 
    // value, if you need to, like in this example 
    Foo(o, x => ((MyStruct)x).Value); 
} 

अद्यतन:

फिर यह करें:

public static void Foo<TUnboxed>(object test) 
        where TUnboxed : struct 
{ 
    try 
    { 
     TUnboxed unboxed = (TUnboxed)test; 
    } 
    catch (InvalidCastException ex) 
    { 
     // handle the exception or re-throw it... 
     throw ex; 
    } 

    // do stuff with 'unboxed' 
} 

public void TestFunc() 
{ 
    // box an int 
    object o = 100; 

    // Now call foo, letting it unbox the int. 
    // Note that the generic type can not be infered 
    // but has to be explicitly given, and has to match the 
    // boxed type, or throws an `InvalidCastException` 
    Foo<int>(o); 
} 
+0

एचएम, नहीं। मुझे अभी भी एक ही समस्या है कि मेरे पास ऑब्जेक्ट ओ है, न कि MyStruct o। मुझे पता है कि रनटाइम पर एक स्ट्रक्चर होना है, लेकिन मुझे संकलन समय पर ठोस प्रकार नहीं पता है। – slurmomatic

+0

@slurmomatic: ठीक है, मेरा उत्तर अपडेट किया गया –

+0

ठीक है, धन्यवाद। हालांकि समस्या बनी हुई है। मुझे नहीं पता कि यह एक int (या MyStruct आदि) है, मुझे केवल इतना पता है कि एक मान प्रकार (संरचना) है। – slurmomatic