Domanda

Scenario:

Attualmente sto scrivendo un livello per astrarre 3 servizi Web simili in una classe utilizzabile. Ogni servizio web espone un insieme di oggetti che condividono la comunanza. Ho creato un insieme di oggetti intermedi che sfruttano la comunanza. Tuttavia nel mio livello devo convertire tra gli oggetti del servizio Web e i miei oggetti.

Ho usato la riflessione per creare il tipo appropriato in fase di esecuzione prima di effettuare la chiamata al servizio Web in questo modo:

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

Ecco il mio codice chiamante, da una delle mie implementazioni di servizio:

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

Quindi ogni servizio espone una diversa "Proprietà" oggetto che nascondo dietro la mia implementazione della mia interfaccia IProperty.

Il codice di riflessione funziona in unit test producendo una matrice di oggetti i cui elementi sono del tipo appropriato. Ma il codice chiamante fallisce:

  

System.InvalidCastException: impossibile   oggetto cast di tipo 'System.Object []'   digitare   'MyProject.Property []

Qualche idea?

Ho avuto l'impressione che qualsiasi cast di Object funzionerà finché l'oggetto contenuto è convertibile?

È stato utile?

Soluzione

Risposta alternativa: generici.

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

Quindi il tuo codice chiamante diventa:

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

Molto più pulito :)

Altri suggerimenti

In sostanza, no. Esistono pochi, limitati usi della covarianza dell'array, ma è meglio semplicemente sapere quale tipo di array si desidera. Esiste un Array.ConvertAll generico che è abbastanza semplice (almeno, è più facile con C # 3.0):

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

La versione C # 2.0 (identica nel significato) è molto meno compatibile con il bulbo oculare:

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

O semplicemente crea una nuova proprietà [] della giusta dimensione e copia manualmente (o tramite Array.Copy ).

Come esempio delle cose che puoi fare con la covarianza dell'array:

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

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

Qui, " asObj " è ancora una proprietà [] - è semplicemente accessibile come oggetto [] . In C # 2.0 e versioni successive, i generici di solito fanno un'opzione migliore della covarianza dell'array.

Come altri hanno già detto, l'array deve essere del tipo giusto per cominciare. Le altre risposte hanno mostrato come convertire un oggetto autentico [] dopo il fatto, ma è possibile creare il giusto tipo di array per iniziare utilizzando Array.CreateInstance :

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

Supponendo che type sia un tipo di riferimento, dovrebbe funzionare: l'array sarà del tipo corretto, ma lo userai come oggetto [] solo per popolarlo.

Non puoi convertire un array come quello: restituisce un array di oggetti, che è diverso da un oggetto. Prova Array.ConvertAll

È corretto, ma ciò non significa che puoi lanciare contenitori di tipo Object su contenitori di altri tipi. Un oggetto [] non è la stessa cosa di un oggetto (sebbene tu, stranamente, potresti lanciare Object [] su Object).

in C # 2.0 puoi puoi farlo usando la riflessione, senza usare generici e senza conoscere il tipo desiderato al momento della compilazione.

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

Dovresti sostituire tutte le chiamate Type.GetType (" OutputData ") e GetProperty (" PropertyName ") con del codice che legge da un file di configurazione.

Vorrei anche usare un generico per dettare la creazione di SomeComplexObject

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

Ma ho detto che non hai bisogno di usare generici.

Nessuna garanzia su prestazioni / efficienza, ma funziona.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top