Невозможно передать объект типа 'System.Object []' в 'MyObject []', что дает?
Сценарий:
В настоящее время я пишу слой для абстрактного 3 похожих веб-сервисов в один пригодный для использования класс. Каждый веб-сервис предоставляет набор объектов, которые обмениваются общими. Я создал набор промежуточных объектов, которые используют общность. Однако в моем слое мне нужно преобразовать объекты веб-службы и мои объекты.
Я использовал отражение для создания соответствующего типа во время выполнения до того, как я сделаю вызов веб-службы следующим образом:
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;
}
Здесь мой код вызова из одной из моих реализаций сервисов:
Property[] props = (Property[])ObjectFactory.CreateProperties(typeof(Property), properties);
_service.SetProperties(folderItem.Path, props);
Таким образом, каждая служба предоставляет другой объект "Свойство", который я скрываю за моей собственной реализацией моего интерфейса IProperty.
Код отражения работает в модульных тестах, создавая массив объектов, элементы которых имеют соответствующий тип. Но вызывающий код выходит из строя:
System.InvalidCastException: невозможно выполнить литой объект типа 'System.Object []' печатать "MyProject.Property []
Любые идеи?
У меня создалось впечатление, что любое нажатие из Object будет работать до тех пор, пока содержащийся объект может быть конвертируемым?
Ответы
Ответ 1
Альтернативный ответ: generics.
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;
}
Затем ваш код вызова будет выглядеть следующим образом:
Property[] props = ObjectFactory.CreateProperties<Property>(properties);
_service.SetProperties(folderItem.Path, props);
Значительная очистка:)
Ответ 2
В принципе, нет. Существует несколько ограниченных возможностей использования ковариации массива, но лучше всего знать, какой тип массива вы хотите. Существует общий Array.ConvertAll, который достаточно прост (по крайней мере, проще с С# 3.0):
Property[] props = Array.ConvertAll(source, prop => (Property)prop);
Версия С# 2.0 (идентичная по смыслу) гораздо менее благоприятна для глаз:
Property[] props = Array.ConvertAll<object,Property>(
source, delegate(object prop) { return (Property)prop; });
Или просто создайте новое свойство [] нужного размера и скопируйте вручную (или через Array.Copy
).
В качестве примера вещей, которые вы можете сделать с ковариацией массива:
Property[] props = new Property[2];
props[0] = new Property();
props[1] = new Property();
object[] asObj = (object[])props;
Здесь "asObj" по-прежнему является Property[]
- он просто доступен как object[]
. В С# 2.0 и выше дженерики обычно делают лучший вариант, чем ковариация массива.
Ответ 3
Как говорили другие, массив должен иметь нужный тип для начала. Другие ответы показали, как преобразовать подлинный объект [] после факта, но вы можете создать правильный тип массива, чтобы начать с использования Array.CreateInstance:
object[] result = (object[]) Array.CreateInstance(type, properties.Length);
Предполагая, что type
является ссылочным типом, это должно работать - массив будет иметь правильный тип, но вы будете использовать его как object[]
для его заполнения.
Ответ 4
Вы не можете преобразовать такой массив - он возвращает массив объектов, который отличается от объекта. Попробуйте Array.ConvertAll
Ответ 5
Это правильно, но это не значит, что вы можете бросать контейнеры типа Object в контейнеры других типов. Объект [] - это не то же самое, что объект (хотя вы, как ни странно, могли бы использовать Object [] для Object).
Ответ 6
в С# 2.0 вы можете сделать это с помощью отражения, не используя generics и не зная желаемого типа во время компиляции.
//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 built in type casting
Array.Copy(newDataArray, pi.GetValue(result, null) as Array, newDataArray.Length);
}
}
Вы хотите заменить все вызовы Type.GetType( "OutputData" ) и GetProperty ( "PropertyName" ) на некоторый код, который читается из файла конфигурации.
Я также использовал бы generic, чтобы диктовать создание SomeComplexObject
T result = new T();
Type resultTypeRef = result.GetType();
Но я сказал, что вам не нужно использовать дженерики.
Отсутствие гарантий производительности/эффективности, но оно работает.