2010-04-09 3 views
4

У меня возникают проблемы с Reflection в C# на данный момент. Приложение, которое я пишу, позволяет пользователю изменять атрибуты определенных объектов с помощью файла конфигурации. Я хочу, чтобы сохранить объектную модель (проект пользователей) в XML. Функция, приведенная ниже, вызывается в середине цикла foreach, перебирая список объектов, которые содержат все остальные объекты в проекте внутри них. Идея заключается в том, что она рекурсивно работает для перевода объектной модели в XML.Невозможно лить списки с отражением в C#

Не беспокойтесь о вызове «Unreal», который слегка изменяет имя объектов, если они содержат определенные слова.

 private void ReflectToXML(object anObject, XmlElement parentElement) 
    { 
    Type aType = anObject.GetType(); 
    XmlElement anXmlElement = m_xml.CreateElement(Unreal(aType.Name)); 
    parentElement.AppendChild(anXmlElement); 
    PropertyInfo[] pinfos = aType.GetProperties(); 
    //loop through this objects public attributes 
    foreach (PropertyInfo aInfo in pinfos) 
    { 
     //if the attribute is a list 
     Type propertyType = aInfo.PropertyType; 
     if ((propertyType.IsGenericType)&&(propertyType.GetGenericTypeDefinition() == typeof(List<>))) 
     { 
      List<object> listObjects = (aInfo.GetValue(anObject,null) as List<object>); 
      foreach (object aListObject in listObjects) 
      { 
       ReflectToXML(aListObject, anXmlElement); 
      } 
     } 
     //attribute is not a list 
     else 
      anXmlElement.SetAttribute(aInfo.Name, ""); 
    } 
    } 

Если атрибуты объекта являются просто строками, то они должны записывать их как строковые атрибуты в XML. Если атрибуты объектов являются списками, тогда он должен рекурсивно вызывать «ReflectToXML», передавая себя в качестве параметра, тем самым создавая вложенную структуру, в которой я нуждаюсь, которая хорошо отражает модель объекта в памяти.

Проблема у меня есть с линией

List<object> listObjects = (aInfo.GetValue(anObject,null) as List<object>); 

Актерский не работает, и он просто возвращает нуль. При отладке я изменил строку

object temp = aInfo.GetValue(anObject,null); 

хлопнул контрольную точку на ней, чтобы увидеть, что «ПолучитьЗначение» возвращался. Он возвращает «Общий список объектов». Конечно, я должен уметь это делать? Досадно, что temp становится общим списком объектов, но поскольку я объявлял temp как особый объект, я не могу его пропустить, потому что у него нет Enumerator.

Как я могу прокручивать список объектов, когда у меня есть только свойство свойств класса?

Я знаю, что в данный момент я сохраню список пустых строк, но это нормально. Я был бы рад видеть, что структура сохранится на данный момент.

Заранее спасибо

ответ

4

дженериков и отражение Дон» t хорошо перемешать, особенно для списков. Я бы сильно предложил использовать (не общий) IList, или если это не сработало (некоторые общие списки не реализуют его), IEnumerableIEnumerable<T> : IEnumerable) и вызовите Add вручную.

Я чувствую вашу боль, действительно (я поддерживаю API-интерфейс сериализации OSS).

+0

Спасибо, человек, который заставил меня задуматься о других способах решения проблемы. Я переключил списки в ArrayLists, и все хорошо. – DrLazer

+0

@DrLazer - Если честно, вам даже не нужно было этого; поскольку 'List <>' и 'ArrayList' реализуют' IList', разговаривают с интерфейсом 'IList', и это не имеет значения, каков конкретный список. –

+0

О, хорошо! Теперь все готово. Спасибо за помощь – DrLazer

1

В C# 3, вы не можете бросить Lists<T> к другим типам Lists<T> даже при забросе на что-то вроде List<Object>. Он явно не разрешен даже при перелистывании в список.

В 4.0 дисперсия немного меняется с интерфейсами с добавлением ключевых слов in and out.

Вот ссылка на Эрика Липперта, объясняющего, как и почему это так.

http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

+4

C# 3.0. Нет C# 3.5. –

+0

К сожалению, я ограничен C# express 2008 – DrLazer

+0

@Kevin - интерфейсы списка не имеют дисперсии, так как они не являются ни 'in', ни' out'. –

5

Я предполагаю, что фактическое значение не List<object>, но что-то вроде List<string> или List<int> или какой-либо другой тип, который не точноobject?

Если это так, то причина, по которой происходит бросок, заключается в том, что общие классы не являются ни ковариаторами, ни контравариантными.

В C# 4.0, однако, вы сможете сделать цикл петли путем литья в IEnumerable<object>, поскольку интерфейсы могут быть взаимно контравариантными.

(много) больше информации здесь: http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx


Edit:

Думая об этом, вам не нужна родовой дисперсии здесь. List<T> реализует не общий IEnumerable. Это все, что нужно для цикла foreach для работы, и вам нужны только элементы типа object, поэтому просто введите его в IEnumerable вместо List<object>, и все должно работать нормально.

+0

Это будет список пользовательских объектов. (Это единственные списки под верхними классами), причина, по которой я использую «объект», состоит в том, что это может быть любой из нескольких списков, содержащих разные типы объектов. Если бы я мог прокрутить этот список и передать объекты обратно в одну и ту же функцию, тогда он должен определить свое имя с именем «aType.Name» и записать его в XML. К сожалению, я ограничен только C# express 2008 – DrLazer

0

Не могли бы вы просто передать их объектам с помощью OfType()?

List<object> listObjects = anObject.OfType<object>().ToList(); 

Update:

Если требование не было для List<object>, это также будет работать и не связаны с дублирования элементов списка:

var enumerableObjects = anObject.OfType<object>(); 
+0

. Свой класс propertyinfo, похоже, не имеет метода OfType. Я использую C# express 2008 – DrLazer

+0

Вам необходимо ссылаться на System.Data.Linq.dll и добавлять с помощью System.Linq; –

+1

Ненавижу говорить об этом, но это очень расточительный подход. Дублирование списка просто для его чтения? Уч. –

Смежные вопросы