Impossible de convertir l'objet de type 'System.Object []' en 'MyObject []', que donne-t-il?

StackOverflow https://stackoverflow.com/questions/212429

Question

Scénario:

J'écris actuellement un calque pour résumer 3 services Web similaires dans une classe utilisable. Chaque service Web expose un ensemble d'objets partageant des points communs. J'ai créé un ensemble d'objets intermédiaires qui exploitent les points communs. Toutefois, dans ma couche, je dois effectuer la conversion entre les objets de service Web et mes objets.

J'ai utilisé la réflexion pour créer le type approprié au moment de l'exécution avant de passer l'appel au 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 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;
    }

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

Chaque service expose donc une "propriété" différente. objet que je cache derrière ma propre implémentation de mon interface IProperty.

Le code de réflexion fonctionne dans des tests unitaires produisant un tableau d'objets dont les éléments sont du type approprié. Mais le code d'appel échoue:

  

System.InvalidCastException: impossible à   Objet cast de type 'System.Object []'   taper   'MyProject.Property []

Des idées?

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

Était-ce utile?

La solution

Réponse alternative: génériques.

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

Votre code d'appel devient alors:

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

Beaucoup plus propre :))

Autres conseils

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<object,Property>(
     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 ).

À titre d'exemple de ce que vous pouvez faire avec la covariance d'un tableau:

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

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

Ici, "asObj" est toujours un Propriété [] - simplement accessible en tant que objet [] . À partir de C 2.0, les génériques constituent généralement une meilleure option que la covariance des tableaux.

Comme d'autres l'ont déjà dit, le tableau doit être du bon type pour commencer. Les autres réponses ont montré comment convertir un objet authentique [] après coup, 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 type est un type de référence, cela devrait fonctionner - le tableau sera du type correct, mais vous l'utiliserez comme objet [] juste pour remplissez-le.

Vous ne pouvez pas convertir un tableau comme celui-ci - il retourne un tableau d'objets, qui est différent d'un objet. Essayez Array.ConvertAll

C'est exact, mais cela ne signifie pas que vous pouvez convertir les conteneurs de type Object en conteneurs d'autres types. Un objet [] n'est pas la même chose qu'un objet (bien que vous puissiez étrangement transtyper Object [] en objet).

en C # 2.0, vous pouvez le faire en utilisant la réflexion, sans utiliser de générique 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 aussi 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 de génériques.

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top