Frage

Szenario:

Ich bin derzeit eine Schicht zu abstrahieren 3 ähnliche Webdiensten in eine nutzbare Klasse zu schreiben. Jeder Webservice stellt eine Reihe von Objekten, die Gemeinsamkeit teilen. Ich habe eine Reihe von Vermittlern Objekten geschaffen, die die Gemeinsamkeit nutzen. Doch in meiner Schicht muss ich zwischen den Web-Service-Objekte und meine Objekte konvertieren.

Ich habe verwendet Reflektion, die geeignete Art zur Laufzeit zu erstellen, bevor ich den Anruf an den Web-Service mache etwa so:

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

Hier ist meine Berufung Code, von einem meiner Service-Implementierungen:

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

So hat jeden Service stellt ein anderes „Property“ Objekt, das ich hinter meiner eigenen Umsetzung meiner IProperty Schnittstelle verbergen.

Der Reflexions Code funktioniert in Tests Einheit ein Array von Objekten, deren Elemente des entsprechenden Typs zu erzeugen. Aber der aufrufende Code fehlschlägt:

  

System.InvalidCastException: Kann nicht   Gussobjekt des Typs ‚System.Object []‘   tippen   ‚MyProject.Property []

Irgendwelche Ideen?

Ich hatte den Eindruck, dass jede Besetzung von Objekt so lange arbeiten, wie das enthaltene Objekt konvertierbar ist?

War es hilfreich?

Lösung

Alternative Antwort. Generika

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

Dann wird Ihr Telefonvorwahl wird:

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

Viele sauberer:)

Andere Tipps

Im Grunde genommen nicht. Es gibt ein paar, begrenzt, Verwendungen von Matrixkovarianz, aber es ist besser, einfach zu wissen, welche Art von Array Sie wollen. Es gibt eine allgemeine Array.ConvertAll ist, das einfach genug ist (zumindest ist es einfacher, mit C # 3.0):

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

Die C # 2.0-Version (identisch in ihrer Bedeutung) ist viel weniger Augapfel freundlich:

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

oder erstellen Sie einfach eine neue Eigenschaft [] die richtige Größe und kopieren Sie manuell (oder über Array.Copy).

Als ein Beispiel für das, was Sie können tun mit Matrixkovarianz:

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

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

Hier "asObj" ist noch ein Property[] - es es einfach als object[] zugänglich. In C # 2.0 und höher, Generika in der Regel eine bessere Option machen als Matrixkovarianz.

Wie bereits gesagt wurde, hat die Anordnung von der richtigen Art, um mit zu beginnen. Die anderen Antworten haben gezeigt, wie ein echtes Objekt [] nach der Tat konvertieren, aber man kann die richtige Art von Array erstellen mit der Verwendung von Array.CreateInstance :

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

Unter der Annahme, type ist ein Referenztyp, sollte diese Arbeit - das Array vom richtigen Typ sein, aber Sie werden es als object[] verwenden nur um es zu füllen

.

Sie können ein Array so konvertieren - es ist ein Array von Objekten zurückkehrt, die von einem Objekt unterscheidet. Versuchen Sie Array.ConvertAll

Das ist richtig, aber das bedeutet nicht, dass Sie Container vom Typ Object auf Behälter anderer Typen werfen können. Ein Object [] ist nicht dasselbe wie ein Objekt (obwohl man könnte seltsam geworfen, Object [] auf Objekt).

in C # 2.0 Sie können tun dies mit Reflexion, ohne die Verwendung von Generika und ohne den gewünschten Typ bei der Kompilierung zu kennen.

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

Sie würden wollen, dass alle Type.GetType ( „Output“) nennt und die GetProperty ( „Propertyname“) mit einigen Code zu ersetzen, die aus einer Konfigurationsdatei liest.

Ich würde auch eine generische verwenden, um die Schaffung von SomeComplexObject zu diktieren

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

Aber ich sage Sie nicht Generika verwenden müssen.

Keine Garantien für Leistung / Effizienz, aber es funktioniert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top