2008-10-17 11 views
10

परिदृश्य:प्रकार की वस्तु कास्ट करने में असमर्थ 'System.Object []' को 'MyObject []', क्या देता है?

मैं वर्तमान में एक समान वर्ग में 3 समान वेबसाइकिलों को सारणी लिख रहा हूं। प्रत्येक webservice वस्तुओं की एक सेट का खुलासा करता है जो समानता साझा करते हैं। मैंने मध्यस्थ वस्तुओं का एक सेट बनाया है जो समानता का फायदा उठाते हैं। हालांकि मेरी परत में मुझे वेब सेवा ऑब्जेक्ट्स और मेरी ऑब्जेक्ट्स के बीच कनवर्ट करने की आवश्यकता है।

मैं रन टाइम पर उचित प्रकार बनाने के लिए प्रतिबिंब का उपयोग किया है इससे पहले कि मैं तो जैसे वेब सेवा से फोन करना:

public static object[] CreateProperties(Type type, IProperty[] properties) 
    { 
     //Empty so return null 
     if (properties==null || properties.Length == 0) 
      return null; 

     //Check the type is allowed 
     CheckPropertyTypes("CreateProperties(Type,IProperty[])",type); 

     //Convert the array of intermediary IProperty objects into 
     // the passed service type e.g. Service1.Property 
     object[] result = new object[properties.Length]; 
     for (int i = 0; i < properties.Length; i++) 
     { 
      IProperty fromProp = properties[i]; 
      object toProp = ReflectionUtility.CreateInstance(type, null); 
      ServiceUtils.CopyProperties(fromProp, toProp); 
      result[i] = toProp; 
     } 
     return result; 
    } 

यहाँ मेरी बुला कोड है, मेरी सेवा कार्यान्वयन में से एक से:

Property[] props = (Property[])ObjectFactory.CreateProperties(typeof(Property), properties); 
_service.SetProperties(folderItem.Path, props); 

इसलिए प्रत्येक सेवा के लिए एक अलग "संपत्ति" वस्तु जो मैं अपने IProperty इंटरफेस के अपने खुद के कार्यान्वयन के पीछे छिपाने के उजागर करता है।

प्रतिबिंब कोड इकाई वस्तुओं जिसका तत्वों उचित प्रकार के होते हैं की एक सरणी के उत्पादन परीक्षण में काम करता है। लेकिन बुला कोड में विफल रहता है:

System.InvalidCastException: प्रकार की डाली वस्तु करने में असमर्थ 'System.Object []' टाइप करने के लिए 'MyProject.Property []

कोई भी विचार?

मैं धारणा है कि वस्तु से किसी भी कलाकारों के रूप में लंबे समय के निहित वस्तु convertable है के रूप में काम करेंगे के तहत किया गया?

उत्तर

9

वैकल्पिक उत्तर: जेनेरिक।

public static T[] CreateProperties<T>(IProperty[] properties) 
    where T : class, new() 
{ 
    //Empty so return null 
    if (properties==null || properties.Length == 0) 
     return null; 

    //Check the type is allowed 
    CheckPropertyTypes("CreateProperties(Type,IProperty[])",typeof(T)); 

    //Convert the array of intermediary IProperty objects into 
    // the passed service type e.g. Service1.Property 
    T[] result = new T[properties.Length]; 
    for (int i = 0; i < properties.Length; i++) 
    { 
     T[i] = new T(); 
     ServiceUtils.CopyProperties(properties[i], t[i]); 
    } 
    return result; 
} 

फिर अपने बुला कोड हो जाता है:

Property[] props = ObjectFactory.CreateProperties<Property>(properties); 
_service.SetProperties(folderItem.Path, props); 

अधिक स्वच्छ :)

+0

ठीक है, मैंने कहा "सी # 2.0 और उसके बाद, जेनेरिक आमतौर पर सरणी कॉन्वर्सिस से बेहतर विकल्प बनाते हैं।" मुझे डर है कि मुझे इसे +1 करने के लिए अपनी आखिरी पोस्ट पर अपना +1 रद्द करना पड़ा था ... मैं आज के लिए बाहर हूं ... –

+0

तर्कसंगत रूप से, यह लंबाई == 0 मामले के लिए थोड़ा सा डोडी देता है - I मैं खुद को एक खाली सरणी वापस भेजता हूं ... –

+0

आरोप हटाने के लिए संपादित :) और हाँ, वापस लौटने की संभावना शायद थोड़ा सा है - लेकिन ओपी के लिए यह तय करना है :) –

4

आप इस तरह की एक सरणी को परिवर्तित नहीं कर सकते हैं - यह वस्तुओं की एक सरणी लौटा रहा है, जो किसी ऑब्जेक्ट से अलग है। Array.ConvertAll

1

यह सही है, लेकिन इसका मतलब यह नहीं है कि आप अन्य प्रकार के कंटेनरों के लिए ऑब्जेक्ट प्रकार के कंटेनर कास्ट कर सकते हैं। एक ऑब्जेक्ट [] एक वस्तु के समान नहीं है (हालांकि आप अजीब तरह से ऑब्जेक्ट [] ऑब्जेक्ट को ऑब्जेक्ट कर सकते हैं)।

+0

ठीक है, पैडेंटिक होने के लिए, और ऑब्जेक्ट [] * एक ऑब्जेक्ट है ... इसलिए कलाकार अजीब नहीं है। सब कुछ एक वस्तु है .NET –

9

असल में, नहीं। सरणी कॉन्वर्सिस के कुछ, सीमित, उपयोग हैं, लेकिन यह जानना बेहतर है कि आप किस प्रकार की सरणी चाहते हैं। एक सामान्य Array.ConvertAll काफी आसान है कि नहीं है (कम से कम, यह सी # 3.0 आसान के साथ है):

Property[] props = Array.ConvertAll(source, prop => (Property)prop); 

सी # 2.0 संस्करण (अर्थ में समान) है बहुत कम नेत्रगोलक के अनुकूल:

Property[] props = Array.ConvertAll<object,Property>(
    source, delegate(object prop) { return (Property)prop; }); 

या दाएं आकार की एक नई संपत्ति [] बनाएं और मैन्युअल रूप से कॉपी करें (या Array.Copy के माध्यम से)।

चीजें आप सरणी सहप्रसरण साथ कर सकते हैं का एक उदाहरण के रूप में:

Property[] props = new Property[2]; 
props[0] = new Property(); 
props[1] = new Property(); 

object[] asObj = (object[])props; 

यहाँ, "asObj" अभी भी एक Property[] है - यह यह बस सुलभ object[] के रूप में। सी # 2.0 और ऊपर में, जेनेरिक आमतौर पर सरणी कॉन्वर्सिस से बेहतर विकल्प बनाते हैं।

+0

धन्यवाद, यह काम करता है। कन्वर्टल बनाम प्रति का प्रदर्शन प्रभाव क्या है? –

+0

कन्वर्टएल प्रत्येक प्रतिनिधि को प्रत्येक बार आमंत्रित करेगा, जहां-जैसे प्रतिलिपि को बफर के तहत बफर.ब्लॉककॉपी का उपयोग करना चाहिए। तो कॉपी जल्दी होना चाहिए। कनवर्ट करें टाइप करना आसान है (और छोटे से मध्यम आकार के लिए ठीक है), और अधिक लचीला: आप गैर-मामूली अनुमान कर सकते हैं। –

+0

इसके अलावा - कनवर्ट सभी को बजाए रूपांतरणों का सामना करना पड़ेगा; Array.Copy ऐसा नहीं कर सकता है, क्योंकि इस बात की कोई गारंटी नहीं है कि मूल और गंतव्य ऑब्जेक्ट एक ही आकार (जो बफर.ब्लॉककॉपी के लिए आवश्यक है) –

5

जैसा कि अन्य ने कहा है, सरणी को शुरू करने के लिए सही प्रकार का होना चाहिए।अन्य उत्तर कैसे इस तथ्य के बाद एक वास्तविक वस्तु [] परिवर्तित करने के लिए पता चला है, लेकिन आप Array.CreateInstance उपयोग करने के साथ शुरू करने के लिए सरणी के सही तरह बना सकते हैं:

object[] result = (object[]) Array.CreateInstance(type, properties.Length); 

type मान लिया जाये कि एक संदर्भ प्रकार है, यह काम करना चाहिए - सरणी सही प्रकार का होगा, लेकिन आप इसका उपयोग इसे बनाने के लिए object[] के रूप में उपयोग करेंगे।

+0

कई बार मैं इस जाल में वैल्यूएटिप्स के साथ गिरता हूं, तो मुझे याद है:) – leppie

+0

महान जानकारी! धन्यवाद, स्टैक ओवरफ्लो को सहायक उत्तरों की आवश्यकता है। इस प्रकार को जानना अच्छा लगेगा लेकिन मैं जितना संभव हो उतना छोटा कोड लिखने की कोशिश कर रहा हूं। इस तरह मैं मैपिंग कोड को फिर से लिखने के बाद बाद में और सेवाएं जोड़ सकता हूं। मुझे वर्तमान में 3 विधियों में 3 लूप लिखना होगा। –

+0

रोब: आप पहले से ही विधि में पैरामीटर के रूप में टाइप कर रहे हैं, है ना? क्या मैंने कुछ गलत समझा है? –

1

सी # में 2.0 आप इस प्रतिबिंब का उपयोग कर सकते हैं, जेनरिक का उपयोग किए बिना और कम से इच्छित प्रकार जानने के बिना समय संकलित करें।

//get the data from the object factory 
object[] newDataArray = AppObjectFactory.BuildInstances(Type.GetType("OutputData")); 
if (newDataArray != null) 
{ 
    SomeComplexObject result = new SomeComplexObject(); 
    //find the source 
    Type resultTypeRef = result.GetType(); 
    //get a reference to the property 
    PropertyInfo pi = resultTypeRef.GetProperty("TargetPropertyName"); 
    if (pi != null) 
    { 
     //create an array of the correct type with the correct number of items 
     pi.SetValue(result, Array.CreateInstance(Type.GetType("OutputData"), newDataArray.Length), null); 
     //copy the data and leverage Array.Copy's built in type casting 
     Array.Copy(newDataArray, pi.GetValue(result, null) as Array, newDataArray.Length); 
    } 
} 

आप चाहते हैं कि कुछ कोड है कि एक कॉन्फ़िग फ़ाइल से पढ़ता के साथ सभी Type.GetType ("OutputData") कॉल और getProperty ("प्रॉपर्टी") को बदलने के लिए।

मैं भी SomeComplexObject

T result = new T(); 
Type resultTypeRef = result.GetType(); 

के निर्माण के हुक्म के लिए एक क्रियाशील का प्रयोग करेंगे लेकिन मैंने कहा आप जेनरिक उपयोग करने की आवश्यकता नहीं किया था।

प्रदर्शन/दक्षता पर कोई गारंटी नहीं है, लेकिन यह काम करता है।

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

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