0

VS2013, Visual Basic

I have a class with many properties.

Public Class
  Property 1
  .
  .
  Property N
End Class

I have a list of name value pairs

name1, value1
.
.
nameN, valueN

The values in the name value pairs will be assigned to the property values.

Does VB have a way that allows me to take one of the names and use it to 'look up' the class property, select it an assign the value to it, looping through the name-value pairs to make all the assignments?

I didn't see a method attached to my Class as I defined it. Should I define my Class differently? I used the Class in the EF6 Code First method to create the backing database.

The alternative as I see it is to list each Class property one by one, looking up the name and assign the value, but that seems like a tedious way of doing things.

Just thought I would ask. Maybe there's a better way to do this.

Thanks.

Best Regards, Alan

Alan
  • 1,587
  • 3
  • 23
  • 43
  • 1
    You can use Reflection to do that. There are a number of components that will automatically map data from one type another, e.g. entity to DTO, that do just that to determine what properties to get and set. – jmcilhinney Nov 25 '14 at 01:06
  • Dim obj As New Example With {.A = "asdf", .B = 42, .C = 3.14} – Hans Passant Nov 25 '14 at 02:21
  • possible duplicate of [Is it possible to pass in a property name as a string and assign a value to it?](http://stackoverflow.com/questions/3443194/is-it-possible-to-pass-in-a-property-name-as-a-string-and-assign-a-value-to-it) – Mark Nov 25 '14 at 04:01
  • @Mark, yes that other post was also useful. Thanks. – Alan Dec 02 '14 at 03:21

1 Answers1

0

There are three classes which will help you; TypeDescriptor, PropertyDescriptor and PropertyDescriptorCollection. They are all located in the System.ComponentModel namespace.

Imports System.ComponentModel

We'll be using the following class for this example:

Public Class Foo
    'Implements ICustomTypeDescriptor (Optional)

    Public Property A() As String
    Public Property B() As Date
    Public Property C() As Integer
    Public Property D() As Boolean

    Public Overrides Function ToString() As String
        Return String.Format("A='{0}', B='{1}', C='{2}', D='{3}'", Me.A, Me.B, Me.C, Me.D)
    End Function

End Class

Get all the properties by invoking the static method GetProperties of the TypeDescriptor class. It returns a collection of PropertyDescriptor classes - your properties. Then you simply invoke either the SetValue and/or GetValue methods. Note that you can implement a custom type descriptor by implementing the ICustomTypeDescriptor interface.

Private Sub RunTest()

    Dim properties As PropertyDescriptorCollection = TypeDescriptor.GetProperties(GetType(Foo))
    Dim ignoreCase As Boolean = True
    Dim foo1 As New Foo()

    properties.Find("A", ignoreCase).SetValue(foo1, "hello")
    properties.Find("B", ignoreCase).SetValue(foo1, Date.Now)
    properties.Find("C", ignoreCase).SetValue(foo1, 1234I)
    properties.Find("D", ignoreCase).SetValue(foo1, True)

    'Get property value:
    'Dim a As String = CType(properties.Find("A", ignoreCase).GetValue(foo1), String)

    Debug.WriteLine(foo1.ToString())

End Sub

Output: (immediate window)

A='hello', B='30.11.2014 11:14:39', C='1234', D='True'


Extension

To expand this even further one can create some extension methods.

Imports System.Runtime.CompilerServices

Public Module Extensions

    <Extension()>
    Public Function GetProperty(Of TComponent)(component As TComponent, propertyName As String, Optional ByVal ignoreCase As Boolean = True) As Object
        Return TypeDescriptor.GetProperties(GetType(TComponent)).Find(propertyName, ignoreCase).GetValue(component)
    End Function

    <Extension()>
    Public Function GetProperty(Of TComponent, TValue)(component As TComponent, propertyName As String, Optional ByVal ignoreCase As Boolean = True) As TValue
        Return CType(TypeDescriptor.GetProperties(GetType(TComponent)).Find(propertyName, ignoreCase).GetValue(component), TValue)
    End Function

    <Extension()>
    Public Sub SetProperty(Of TComponent)(instance As TComponent, propertyName As String, value As Object, Optional ByVal ignoreCase As Boolean = True)
        TypeDescriptor.GetProperties(GetType(TComponent)).Find(propertyName, ignoreCase).SetValue(instance, value)
    End Sub

End Module

Now it's very easy to set/get a property value by name.

Private Sub RunTest()

    Dim foo1 As New Foo()

    foo1.SetProperty("A", "hello")
    foo1.SetProperty("B", Date.Now)
    foo1.SetProperty("C", 1234I)
    foo1.SetProperty("D", True)

    'Get property value:
    'Dim a As String = CType(foo1.GetProperty("A"), String)
    'Dim a As String = foo1.GetProperty(Of String)("B")

    Debug.WriteLine(foo1.ToString())

End Sub

Output:

A='hello', B='30.11.2014 11:18:17', C='1234', D='True'

Bjørn-Roger Kringsjå
  • 9,849
  • 6
  • 36
  • 64
  • That was great, thanks. Able to replicate part 1 of your answer which truly answered my original question. I wasn't able to replicate part 2 only because I'm not familiar yet with the extensions concept, but I could follow in your code how it worked. – Alan Dec 02 '14 at 17:47
  • Great! The concept of extension methods isn't that hard. Just add a new class file to your project and replace the auto generated code with my extension module code, rebuild. You can read more about extension methods **[here](http://msdn.microsoft.com/en-us/library/bb384936.aspx)**. – Bjørn-Roger Kringsjå Dec 02 '14 at 17:54