VB.NET: создание экземпляра вложенного свойства путем отражения

Я хочу установить значения свойств с помощью отражения. В этом потоке они предложить решение. Но проблема с решением заключается в том, что оно не создает экземпляры свойств. Но я хочу проверить и создать экземпляр свойств, если это необходимо. Мой ДТО:

Public Class root
    Public Property Printing() As rootPrinting
End Class

Public Class rootPrinting
    Public Property Printer() As String
    Public Property PrinterBatch() As String
End Class

Теперь для установки свойств я определил следующую функцию:

Public Sub SetProperty(ByVal target As Object, ByVal compoundProperty As String, ByVal value As Object)
    Dim properties As String() = compoundProperty.Split("."c)
    For i As Integer = 0 To properties.Length - 1 - 1
        Dim propertyToGet As PropertyInfo = target.[GetType]().GetProperty(properties(i))
        target = propertyToGet.GetValue(target, Nothing)
        if IsNothing(target) then
            if propertyToGet.PropertyType.IsClass then
                target = Activator.CreateInstance(propertyToGet.PropertyType)
            End If
        End If
    Next

    Dim propertyToSet As PropertyInfo = target.[GetType]().GetProperty(properties.Last())
    propertyToSet.SetValue(target, value, Nothing)
End Sub

Тогда я называю это так:

Dim configObject as New root
SetProperty(configObject , "Printing.Printer","skjfkd")

Если перед вызовом SetProperty(configObject,...) я создам экземпляр configObject.Printing, то он будет работать нормально:

Dim configObject as New root
configObject.Printing = new rootPrinting()
SetProperty(configObject , "Printing.Printer","skjfkd") 

В противном случае после вызова SetProperty(...) configObject.Printing будет Nothing.
Кажется, что при вызове Activator.CreateInstance(propertyToGet.PropertyType) теряется ссылка на исходный объект. Пока объект в функции действительно инициализирован, основным объектом остается Nothing. Как я могу правильно создать экземпляр свойства класса?


person Code Pope    schedule 20.08.2018    source источник
comment
В вашем примере классы DTO имеют общедоступные конструкторы и свойства. Я предполагаю, что в реальном проекте все они частные?   -  person Parrish Husband    schedule 21.08.2018
comment
@ParrishHusband Нет, в реальном проекте свойства тоже общедоступны. Там просто у меня есть частные члены, которые привязаны к свойствам. Но чтобы сократить текст, я изменил его для этого образца.   -  person Code Pope    schedule 21.08.2018


Ответы (2)


Этот вопрос/ответ был мне очень полезен (спасибо Code Pope!), мне нужен был такой же код на С#:

public void SetProperty(object target, string compoundProperty, object value)
{
    var properties = compoundProperty.Split('.');

    for (int i=0; i < (properties.Length - 1); i++)
    {
        var propertyToGet = target.GetType().GetProperty(properties[i]);
        var property_value = propertyToGet.GetValue(target, null);
        if (property_value == null)
        {
            if (propertyToGet.PropertyType.IsClass)
            {
                property_value = Activator.CreateInstance(propertyToGet.PropertyType);
                propertyToGet.SetValue(target, property_value);
            }
        }
        target = property_value;
    }

    var propertyToSet = target.GetType().GetProperty(properties.Last());
    propertyToSet.SetValue(target, value);
}
person David McClelland    schedule 02.01.2019

Ok. Проблема была решена. Чтобы решить проблему, код должен быть изменен следующим образом:

Public Sub SetProperty(ByVal target As Object, ByVal compoundProperty As String, ByVal value As Object)

   Dim properties As String() = compoundProperty.Split("."c)

   For i As Integer = 0 To properties.Length - 1 - 1
      Dim propertyToGet As PropertyInfo = target.GetType().GetProperty(properties(i))
      Dim property_value = propertyToGet.GetValue(target, Nothing)
      If IsNothing(property_value) Then
         If propertyToGet.PropertyType.IsClass Then
            property_value = Activator.CreateInstance(propertyToGet.PropertyType)
            propertyToGet.SetValue(target, property_value)
         End If
      End If
      target = property_value
   Next

   Dim propertyToSet As PropertyInfo = target.GetType().GetProperty(properties.Last())
   propertyToSet.SetValue(target, value)

End Sub
person Code Pope    schedule 21.08.2018