Невозможно привести объект типа «System.Object []» к «MyObject []», что дает? - PullRequest
11 голосов
/ 17 октября 2008

Сценарий:

В настоящее время я пишу слой для абстрагирования 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 будет работать, пока содержащийся объект конвертируем?

Ответы [ 6 ]

9 голосов
/ 17 октября 2008

Альтернативный ответ: дженерики.

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

намного чище:)

9 голосов
/ 17 октября 2008

В основном нет. Существует несколько ограниченных вариантов использования ковариации массива, но лучше просто знать, какой тип массива вы хотите. Существует универсальный Array.ConvertAll, который достаточно прост (по крайней мере, проще в C # 3.0):

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

Версия C # 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" - это все еще a Property[] - это просто доступно как object[]. В C # 2.0 и выше дженерики обычно делают лучший выбор, чем ковариация массива.

5 голосов
/ 17 октября 2008

Как уже говорили другие, массив должен иметь правильный тип для начала. Другие ответы показали, как преобразовать подлинный объект [] после факта, но вы можете создать правильный тип массива, чтобы начать с использования Array.CreateInstance :

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

Предполагая, что type является ссылочным типом, это должно работать - массив будет иметь правильный тип, но вы будете использовать его как object[] просто для заполнения.

4 голосов
/ 17 октября 2008

Вы не можете преобразовать массив таким образом - он возвращает массив объектов, который отличается от объекта. Попробуйте Array.ConvertAll

1 голос
/ 20 июля 2010

в C # 2.0 вы можете сделать это с помощью отражения, без использования обобщений и без знания требуемого типа во время компиляции.

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

Вы хотели бы заменить все вызовы Type.GetType ("OutputData") и GetProperty ("PropertyName") на некоторый код, считываемый из файла конфигурации.

Я бы также использовал универсальный, чтобы продиктовать создание SomeComplexObject

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

Но я сказал, что вам не нужно использовать дженерики.

Нет гарантий по производительности / эффективности, но это работает.

1 голос
/ 17 октября 2008

Это правильно, но это не значит, что вы можете приводить контейнеры типа Object к контейнерам других типов. Object [] - это не то же самое, что Object (хотя вы, как ни странно, могли бы привести Object [] к Object).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...