Search code examples
.netvb.netunit-testingreflectionassert

.NET Generics, pull object member value by name


I am passing in 2 generic objects and a string into a function and I would like to find the property of the objects that match the string and compare their values.

Here is a sample model:

Public Structure Foo
    Public Bar As String
    Public Nan As String
    Public Tucket As String
End Structure

and the calling class:

<TestMethod()> 
Public Sub TestEquality_Class_Pass_Identifier()
    _tester = new GeneralAssert
    Dim expectedFoo = New Foo With {.Bar = "asdf", .Nan = "zxcv", .Tucket = "qwer"}
    Dim actualFoo = New Foo With {.Bar = "qwer", .Nan = "zxcv", .Tucket = "qwer"}
    _tester.TestEquality(expectedFoo, actualFoo, "Bar")
End Sub

The Generic Assert class that will be doing the business logic

Public Class GenericAssert
    Public Sub TestEquality(Of t)(expected As t, actual As t, Optional identifier As String = Nothing)
        Dim expectedType = expected.GetType(), actualType = actual.GetType()
        Assert.AreEqual(expectedType, actualType)

        If (Not identifier Is Nothing) Then
            Dim expectedProperty = expectedType.GetMember(identifier).FirstOrDefault()
            Dim actualProperty = actualType.GetMember(identifier).FirstOrDefault()

            TestEquality(*WhatHere1*, *WhatHere2*)
        End If
    End Sub
End Class

The expected outcome will be that the Bar member of expectedFoo ("asdf") and actualFoo ("qwer") would be compared. I cannot find any value in FieldInfo, PropertyInfo or MemberInfo that will allow me to get the value assigned to that property by name.


Solution

  • Because both the nature of the structure and the what is being tested for is known, I used FieldInfo objects as the most straight forward way to get the field values.

    Public Sub TestEquality(Of t)(expected As t, actual As t, Optional identifier As String = Nothing)
        Dim expectedType = expected.GetType()
        Dim actualType = actual.GetType()
    
        Assert.AreEqual(expectedType, actualType)
    
        If (identifier IsNot Nothing) Then
            Dim expectedField As FieldInfo = expectedType.GetField(identifier, BindingFlags.IgnoreCase Or BindingFlags.Public Or BindingFlags.Instance)
            Dim actualField As FieldInfo = actualType.GetField(identifier, BindingFlags.IgnoreCase Or BindingFlags.Public Or BindingFlags.Instance)
    
            Assert.AreEqual(expectedField.GetValue(expected), actualField.GetValue(actual))
        End If
    End Sub