Impossible de convertir l’object de type ‘System.Object ‘ en ‘MyObject ‘, que donne-t-il?

Scénario:

J’écris actuellement une couche pour résumer 3 services Web similaires dans une classe utilisable. Chaque service Web expose un ensemble d’objects partageant des points communs. J’ai créé un ensemble d’objects intermédiaires qui exploitent les points communs. Cependant, dans ma couche, je dois convertir entre les objects de service Web et mes objects.

J’ai utilisé la reflection pour créer le type approprié au moment de l’exécution avant d’appeler le service Web, comme suit:

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 eg 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; } 

Voici mon code d’appel, issu d’une de mes implémentations de service:

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

Ainsi, chaque service expose un object “Propriété” différent que je cache derrière ma propre implémentation de mon interface IProperty.

Le code de reflection fonctionne dans des tests unitaires produisant un tableau d’objects dont les éléments sont du type approprié. Mais le code d’appel échoue:

System.InvalidCastException: impossible de convertir l’object de type ‘System.Object []’ en ‘MyProject.Property []

Des idées?

J’avais l’impression que tous les acteurs d’Object fonctionneront tant que l’object contenu sera convertible?

Réponse alternative: génériques.

 public static T[] CreateProperties(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 eg 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; } 

Ensuite, votre code d'appel devient:

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

Beaucoup plus propre 🙂

En gros non. Il existe quelques utilisations limitées de la covariance de tableaux, mais il est préférable de simplement savoir quel type de tableau vous voulez. Il existe un tableau générique Array.ConvertAll qui est assez simple (du moins, c’est plus facile avec C # 3.0):

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

La version C # 2.0 (dont le sens est identique) est beaucoup moins conviviale:

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

Ou créez simplement une nouvelle propriété [] de la bonne taille et copiez-la manuellement (ou via Array.Copy ).

Voici un exemple de ce que vous pouvez faire avec la covariance de tableau:

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

Ici, “asObj” est toujours une Property[] – simplement accessible en tant object[] . En C # 2.0 et supérieur, les génériques constituent généralement une meilleure option que la covariance par tableau.

Comme d’autres l’ont dit, le tableau doit être du bon type pour commencer. Les autres réponses ont montré comment convertir un object authentique [] après le fait, mais vous pouvez créer le bon type de tableau pour commencer avec Array.CreateInstance :

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

En supposant que le type soit un type de référence, cela devrait fonctionner – le tableau sera du type correct, mais vous l’utiliserez comme un object[] pour le remplir.

Vous ne pouvez pas convertir un tableau comme celui-ci – il renvoie un tableau d’objects, ce qui est différent d’un object. Essayez Array.ConvertAll

C’est exact, mais cela ne signifie pas que vous pouvez transtyper des conteneurs de type Object vers des conteneurs d’autres types. Un object [] n’est pas la même chose qu’un object (même si, étrangement, vous pouvez convertir un object [] en object).

en C # 2.0, vous pouvez le faire en utilisant la reflection, sans utiliser de génériques ni connaître le type souhaité au moment de la compilation.

 //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); } } 

Vous souhaitez remplacer tous les appels Type.GetType (“OutputData”) et GetProperty (“PropertyName”) par du code lu à partir d’un fichier de configuration.

Je voudrais également utiliser un générique pour dicter la création de SomeComplexObject

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

Mais j’ai dit que vous n’aviez pas besoin d’utiliser des génériques.

Aucune garantie de performance / efficacité, mais cela fonctionne.