2014-10-16 2 views
0

Мне нужно выполнить итерацию по всей структуре класса. Я допрашиваю объекты, отправленные в мои методы WCF, и теперь у меня есть перегрузка ToString() в каждом из моих классов, которые перечисляют все свойства и их значения. Это работает; но жестко запрограммирован и требует обновлений при каждом добавлении свойств в класс.Reflection - Iterating Class со свойствами, которые являются классами

Текущее решение - VB, но следующей версией будет C# - следовательно, оба тега.

Класс может состоять только из примитивных типов или класс может состоять из других объектов. Итерация через простой класс не является проблемой.

У меня возникли проблемы с идентификацией, когда недвижимость на самом деле является другим классом. Итак, с учетом приведенного ниже примера, я могу выполнять итерацию через Назначение и Пациент и выгружать значения каждого из их свойств.

Я застреваю, пытаясь пронестись через PatientAppointment. Я просмотрел MSDN и SO, попробовал бесчисленные свойства внутри этого типа и т. Д., Но безрезультатно.

Public Class PatientAppointment 
    Public Property Pat As Patient 
    Public Property Appt As Appointment 
End Class 

Public Class Appointment 
    Public Property ApptProp1 As String 
    Public Property ApptProp2 As Integer 
End Class 

Public Class Patient 
    Public Property PatProp1 As String 
    Public Property PatProp2 As Integer 
End Class 
+0

И какая ошибка вы получаете? – BradleyDotNET

+1

Как именно вы хотите перебрать «PatientAppointment»? Вы хотите итеративно рекурсивно (перебирать каждое свойство «PatientAppointment», а также каждое свойство 'Pat' и' Appt')? Или вы просто хотите знать, является ли свойство классом или нет? –

+0

- Я не получаю сообщение об ошибке. –

ответ

0

Возможно, вы ищете способ идентифицировать свои типы с определенным уровнем уверенности. Одним из способов может быть использование настраиваемого атрибута, который будет легко найти и фильтровать с помощью Reflection.

Public Class RealMcCoy 
    Inherits Attribute 

    Public Property IsReal As Boolean 

    Public Sub New(b as Boolean) 
     IsReal = b 
    End Sub 
End Class 

<RealMcCoy(True)>  
Public Class Patient 
    ... 
End Class 

<RealMcCoy(True)> 
Public Class Appointment 
    ... 
End Class 

Теперь при переборе свойств, проверьте, если это RealMcCoy, чтобы увидеть, если это тот, который вы хотите/нужно просверлить в. Так как атрибут будет на тип, есть дополнительный шаг, чтобы получить тип каждого свойства и опрашивать что

Dim props As PropertyInfo() = myFoo.GetType.GetProperties 
    Dim pt As Type 

    For Each pi As PropertyInfo In props 
     pt = pi.PropertyType   ' get the property type 

     Dim attr() As RealMcCoy = 
       DirectCast(pt.GetCustomAttributes(GetType(RealMcCoy), True), RealMcCoy()) 
     If attr.Length > 0 Then 
      ' bingo, baby...optional extra test: 
      If attr(0).IsReal Then 
       Console.Beep() 
      End If 
     Else 
      ' skip this prop - its not a real mccoy 
     End If 
    Next 
End Sub 

Он ломает, если вы добавите тип И не добавить атрибут, но менее хрупким, чем чтобы обновить каждый тип для своих составных свойств. Поддельный интерфейс будет проще запрашивать, но имеет тот же недостаток.

Я не уверен, что понимаю проблему «игр» - вы боитесь, что некоторые другие типы будут подняты? Атрибуты были бы трудными для «игры», поскольку они были скомпилированы в сборку, но все же вышеупомянутое может быть использовано для возврата GUID (возможно, одного, прикрепленного к сборке?), А не bool, чтобы обеспечить некоторую уверенность.

Абсолютная уверенность будет трудно найти.


Атрибут RealMcCoy вероятно, не будут применяться к вашим топ типов уровня (PatientAppointment) только типы (классы), которые будут использоваться в качестве свойств других типов. Объект является способом их легко идентифицировать.

В зависимости от того, как он используется, словарь или хеш-таблица пар типаName-PropertyName уже, идентифицированные как RealMcCoys, могут быть полезны, поэтому весь процесс Reflection может быть закорочен. Вместо того, чтобы добавлять «на лету», вы можете составить список целиком в целом как shown in this answer - см. Процедуру RangeManager.BuildPropMap.

Я не очень уверен в подходе к наследованию, поскольку вы, возможно, захотите на самом деле использовать наследование. Интерфейс может работать лучше: изначально его простое существование может быть триггером с самого начала, но также может использоваться для предоставления услуги.


Простой тест:

' B and C classes are not tagged 
Friend Class FooBar 
    Public Property Prop1 As PropA 
    Public Property Prop2 As PropB 
    Public Property Prop3 As PropC 
    Public Property Prop4 As PropD 
    Public Property Prop5 As PropE 
End Class 

Добавить строку в цикл:

Dim f As New FooBar 
' use instance: 
Dim props As PropertyInfo() = f.GetType.GetProperties 
Dim pt As Type 

For Each pi As PropertyInfo In props 
    pt = pi.PropertyType 

    Dim attr() As RealMcCoy = 
      DirectCast(pt.GetCustomAttributes(GetType(RealMcCoy), True), RealMcCoy()) 

    Console.WriteLine("Prop Name: {0}, prop type: {1}, IsRealMcCoy? {2}", 
      pi.Name, pt.Name, If(attr.Length > 0, "YES!", "no")) 
Next 

Выход:

Prop Name: Prop1 prop type: PropA IsRealMcCoy? YES! 
Prop Name: Prop2 prop type: PropB IsRealMcCoy? no 
Prop Name: Prop3 prop type: PropC IsRealMcCoy? no 
Prop Name: Prop4 prop type: PropD IsRealMcCoy? YES! 
Prop Name: Prop5 prop type: PropE IsRealMcCoy? YES! 
+0

другим способом было бы сделать каждый класс используемым наследованием от базового класса 'McCoy' и просто проверить, есть ли тип' IsAssignableFrom' как сигнал – Plutonix

+0

Hi Plutonix, я играю с этим сейчас. Мне также нравится идея IsAssignableFrom и может использовать ее в версии C#, поскольку я планирую наследовать от нескольких классов в этой версии. Так или иначе, у меня есть вопрос по вашему образцу. Где вы говорите dim attr() как mccoy, что должно быть на самом деле? Я попробовал realmccoy, но я получаю пустой список для attr(). –

+0

Я сделал редактирование - это должен быть «RealMcCoy» - я пытался избежать «RealMcCoy.IsRealMcCoy» и сбросил некоторые символы. Очевидно, будет много реквизитов на тип, который * не * имеет attr, но те, у кого есть это, должны появиться. Это рабочий/проверенный код (сейчас). – Plutonix

0

Большое спасибо Plutonix! Вот моя последняя функция. Если мой ответ отменяет ответ Плутоникса, тогда мне нужно будет его скорректировать, поскольку он полностью заслуживает признания за то, что он довел меня до этого момента.

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

Function IterateClass(ByVal o As Object, ByVal topLevelFlag As Boolean, ByVal indentLevel As Integer) As String 

    Dim retVal As New StringBuilder 

    Try 

     '' Iterate top level of supplied type '' 
     '' Query each property for custom attribute ADMICompositeClassAttribute '' 
     '' If exists and set to true then we're dealing with a base class that we need to break down recursively '' 
     '' If not then immediately dump this type's properties '' 


     '' Build header of output '' 
     If topLevelFlag Then 

      '' <<EXCERPTED>> '' 

     End If 


     '' We start walking through the hierarchy here, no matter how much we recurse we still need to do this each time '' 
     Dim properties_info As PropertyInfo() 
     properties_info = o.GetType().GetProperties() 

     For Each p As PropertyInfo In properties_info 
      Dim propName As String = p.Name 
      Dim propTypeList As List(Of String) = p.PropertyType.ToString().Split(".").ToList() 
      Dim propType As String = propTypeList(propTypeList.Count - 1).Replace("[", "").Replace("]", "") 
      Dim pValue As Object = Nothing 

      '' We check this type for custom attribute ADMICompositeClassAttribute '' 
      '' Is this type a composite? '' 
      Dim oAttr() As ADMICompositeClassAttribute = p.PropertyType.GetCustomAttributes(GetType(ADMICompositeClassAttribute), False) 
      Dim indentString As String = String.Concat(Enumerable.Repeat(" ", indentLevel)) 
      If oAttr.Length > 0 AndAlso oAttr(0).IsComposite Then 

       '' This is a nested type, recurse it '' 
       Dim dynType As Type = p.PropertyType() 
       Dim dynObj As Object = Activator.CreateInstance(dynType) 

       '' <<EXCERPTED '' 

      Else 

       pValue = p.GetValue(o, Nothing) 

      End If 

     Next 


    Catch ex As Exception 
     retVal.AppendLine(ex.ToString()) 

    End Try 
    Return retVal.ToString() 


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