1

I want to set the values of the properties via reflection. In this thread they propose a solution. But the problem with the solution is that it is not instantiating the properties. But I want to check and instantiate the properties if necessary. My DTO is:

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

Now for setting the properties I have defined the following function:

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

Then I call it like this:

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

If before calling SetProperty(configObject,...) I instantiate configObject.Printing then it will work fine:

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

Otherwise after calling SetProperty(...), configObject.Printing will be Nothing.
It seems that when calling Activator.CreateInstance(propertyToGet.PropertyType) the reference to the original object is lost. While the object in the function is really initialized, the main object remains Nothing. How can I instantiate the class property correctly?

Community
  • 1
  • 1
Code Pope
  • 4,649
  • 6
  • 22
  • 53
  • The DTO classes have public constructors and properties in your example. I assume in the actual project these are all private? – Parrish Husband Aug 20 '18 at 22:51
  • @ParrishHusband No, in the actual project the the properties are public, too. There just I have private members which are bound to the properties. But to shorten the text I have changed it for this sample. – Code Pope Aug 21 '18 at 06:01

2 Answers2

2

This question/answer was very helpful to me (thanks Code Pope!), I needed the same code in C#:

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);
}
David McClelland
  • 2,563
  • 4
  • 25
  • 35
1

Ok. The problem was solved. To solve the problem the code has to be modified as following:

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
Code Pope
  • 4,649
  • 6
  • 22
  • 53