Não é possível para objeto fundido do tipo 'System.Object []' para 'MyObject []', o que dá?
-
03-07-2019 - |
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?
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.