Não é possível para objeto fundido do tipo 'System.Object []' para 'MyObject []', o que dá?

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

Pergunta

Cenário:

Atualmente estou escrevendo uma camada de abstrair 3 webservices semelhantes em uma classe utilizável. Cada webservice expõe um conjunto de objetos que comunalidade ação. Eu criei um conjunto de objetos intermediários que exploram a comunhão. No entanto, em minha camada Eu preciso converter entre os objetos de serviços web e os meus objetos.

Eu usei reflexão para criar o tipo adequado em tempo de execução antes de eu fazer a chamada para o serviço web assim:

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

Aqui está o meu código de chamada, de uma das minhas implementações de serviço:

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

Assim, cada serviço expõe um objeto diferente "Propriedade", que eu me escondo atrás da minha própria implementação da minha interface IProperty.

O código reflexão trabalha em testes de unidade produzindo uma matriz de objetos cujos elementos são do tipo apropriado. Mas o código de chamada falhar:

System.InvalidCastException: a Unable objeto fundido do tipo 'System.Object []' digitar 'MyProject.Property []

Todas as idéias?

Eu estava sob a impressão de que qualquer elenco do objeto irá funcionar, desde que o objeto contido é conversível?

Foi útil?

Solução

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

Em seguida, o código de chamada torna-se:

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

Muito mais limpo:)

Outras dicas

Basicamente, não. Existem alguns, limitado, usos de covariância matriz, mas é melhor do que simplesmente saber que tipo de matriz que você deseja. Há uma Array.ConvertAll genérico que é fácil o suficiente (pelo menos, é mais fácil com C # 3.0):

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

O C # 2.0 versão (idêntico em significado) é muito menos globo ocular friendly:

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

Ou apenas criar uma nova propriedade [] do tamanho certo e copiar manualmente (ou via Array.Copy).

Como um exemplo das coisas que você pode fazer com covariância matriz:

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

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

Aqui, "asObj" é ainda a Property[] - é simplesmente acessível como object[]. No C # 2.0 e acima, os genéricos costumam fazer uma opção melhor do que covariância matriz.

Como já foi dito, a matriz tem que ser do tipo certo para começar. As outras respostas têm mostrado como converter um objeto genuíno [] após o fato, mas você pode criar o tipo certo de matriz para iniciar com o uso de Array.CreateInstance :

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

Assumindo type é um tipo de referência, isso deve funcionar -. A matriz será do tipo correto, mas você vai usá-lo como um object[] apenas para preenchê-lo

Você não pode converter uma matriz assim - ele está retornando um array de objetos, que é diferente de um objeto. Tente Array.ConvertAll

Isso é correto, mas isso não significa que você pode lançar recipientes do tipo Object para recipientes de outros tipos. Um Object [] não é a mesma coisa que um objeto (embora você, estranhamente, poderia lançar Object [] para Object).

em C # 2.0 você pode fazer isso usando a reflexão, sem o uso de genéricos e sem saber o tipo desejado em tempo de compilação.

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

Você gostaria de substituir todos os Type.GetType ( "OutputData") chamadas e o GetProperty ( "PropertyName") com algum código que lê a partir de um arquivo de configuração.

Também gostaria de usar um genérico para ditar a criação de SomeComplexObject

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

Mas eu disse que não tinha necessidade de genéricos de uso.

Não há garantias sobre o desempenho / eficiência, mas ela não funciona.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top