Pregunta

Escenario:

Actualmente estoy escribiendo una capa para abstraer 3 servicios web similares en una clase utilizable. Cada servicio web expone un conjunto de objetos que comparten puntos en común. He creado un conjunto de objetos intermedios que explotan lo común. Sin embargo, en mi capa necesito convertir entre los objetos del servicio web y mis objetos.

He utilizado la reflexión para crear el tipo adecuado en el tiempo de ejecución antes de hacer la llamada al servicio web, por lo que:

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

Aquí está mi código de llamada, de una de mis implementaciones de servicio:

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

Entonces, cada servicio expone una " Propiedad " " objeto que oculto detrás de mi propia implementación de la interfaz de mi IProperty.

El código de reflexión funciona en pruebas unitarias produciendo una matriz de objetos cuyos elementos son del tipo apropiado. Pero el código de llamada falla:

  

System.InvalidCastException: no se puede   objeto fundido de tipo 'System.Object []'   digitar   'MyProject.Property []

¿Alguna idea?

Tenía la impresión de que cualquier conversión desde Objeto funcionará siempre que el objeto contenido sea convertible?

¿Fue útil?

Solución

Respuesta alternativa: genéricos.

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

Entonces su código de llamada se convierte en:

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

Mucho más limpio :)

Otros consejos

Básicamente, no. Hay algunos usos limitados de la covarianza de la matriz, pero es mejor simplemente saber qué tipo de matriz desea. Hay un Array.ConvertAll genérico que es bastante fácil (al menos, es más fácil con C # 3.0):

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

La versión C # 2.0 (idéntica en significado) es mucho menos amigable con los ojos:

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

O simplemente cree una nueva Propiedad [] del tamaño correcto y cópiela manualmente (o mediante Array.Copy ).

Como ejemplo de las cosas que puede hacer con la covarianza de matriz:

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

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

Aquí, " asObj " es todavía una propiedad [] ; es simplemente accesible como object [] . En C # 2.0 y superior, los genéricos generalmente son una mejor opción que la covarianza de matriz.

Como han dicho otros, la matriz debe ser del tipo correcto para empezar. Las otras respuestas han mostrado cómo convertir un objeto genuino [] después del hecho, pero puede crear el tipo correcto de matriz para comenzar usando Array.CreateInstance :

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

Suponiendo que type es un tipo de referencia, esto debería funcionar: la matriz será del tipo correcto, pero la usará como un objeto [] solo para poblarlo.

No puedes convertir una matriz de esa manera: está devolviendo una matriz de objetos, que es diferente de un objeto. Pruebe Array.ConvertAll

Eso es correcto, pero eso no significa que pueda convertir contenedores de tipo Object en contenedores de otros tipos. Un Objeto [] no es lo mismo que un Objeto (aunque, extrañamente, podría lanzar Objeto [] a Objeto).

en C # 2.0 usted puede hacer esto usando la reflexión, sin usar genéricos y sin saber el tipo deseado en el momento de la compilación.

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

Desearía reemplazar todas las llamadas Type.GetType (" OutputData ") y GetProperty (" PropertyName ") con algún código que se lea desde un archivo de configuración.

También usaría un genérico para dictar la creación de SomeComplexObject

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

Pero dije que no era necesario usar genéricos.

No hay garantías de rendimiento / eficiencia, pero funciona.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top