0

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.

theB3RV
  • 894
  • 4
  • 13
  • 33
  • `.GetValue()` won't do it? – John Alexiou Aug 01 '14 at 18:45
  • `expectedId.GetValue()` expects me to pass in an object, but expectedId is the Bar object so I have nothing to pass in. `expected` does not have a `.GetValue()` – theB3RV Aug 01 '14 at 18:50
  • `expectedProperties.GetValue()` sine you have established it is named `identifier`. You pass the instance `expectedFoo` – John Alexiou Aug 01 '14 at 18:56
  • `expectedProperties` is of type `MemberInfo()`. `expectedProperties.GetValue(expectedId)` has a compiler error "Incorrect argument types. Candidates are Integer or Long. – theB3RV Aug 01 '14 at 19:00
  • It would help if you provided an example so we understand what/why you are doing. Like some sample classes this is going to be used with, how to call it, and the expected result. – John Alexiou Aug 01 '14 at 19:02
  • see edit for more details – theB3RV Aug 01 '14 at 19:10
  • Maybe you should rename the class to `AnonymousType` and the method `AssertEqual()` to be more descriptive of what you are doing. The difference being between generic types and anonymous types which is what you are handling. – John Alexiou Aug 01 '14 at 19:12
  • I dont understand what you mean? this class is my own built class...`AssertEqual` is a prebuilt unit testing feature that compares 2 values and throws an exception if they are not equal – theB3RV Aug 01 '14 at 19:14
  • You are comparing anonymous types (http://msdn.microsoft.com/en-us/library/bb384767.aspx). The term generic has a different meaning. – John Alexiou Aug 01 '14 at 19:15
  • *whatHere1* needs to evaluate to "asdf" and *whatHere2* needs to evaluate to "qwer" – theB3RV Aug 01 '14 at 19:16
  • See relevant article http://visualstudiomagazine.com/blogs/tool-tracker/2012/06/comparing-anonymous-objects-in-c-sharp-and-vb.aspx – John Alexiou Aug 01 '14 at 19:17
  • I don't think you fully understand the problem. I don't know beforehand which property is being compared...i need to get the value of a property based on the name the user passes in... – theB3RV Aug 01 '14 at 19:19
  • Is the name known compile type, or runtime only? – John Alexiou Aug 01 '14 at 19:20
  • what you see is what I have, `_tester.TestEquality(expectedFoo, actualFoo, "Bar")` is when the function knows what member to compare – theB3RV Aug 01 '14 at 19:22
  • 3
    It looks like you are trying to write reusable unit tests to compare objects; you may want to take a look at [AutoFixture](https://github.com/AutoFixture/AutoFixture)'s *Idioms* and *SemanticComparison* sub-projects, as well as [Albedo](https://github.com/ploeh/Albedo). – Mark Seemann Aug 04 '14 at 15:47

2 Answers2

1

I do not understand why this won't do in this case:

Public Sub AssertEquality(Of T)(ByVal expected As T, ByVal actual As T, identifier As String)

    Dim expected_prop = expected.GetType().GetProperty(identifier, BindingFlags.Instance + BindingFlags.Public)
    Dim actual_prop = actual.GetType().GetProperty(identifier, BindingFlags.Instance + BindingFlags.Public)

    Dim expected_value = expected_prop.GetValue(expected, Nothing)
    Dim actual_value = actual_prop.GetValue(actual, Nothing)

    Assert.AreEqual(expected_value, acutal_value)

End Sub

Sub Main()

    Dim expectedFoo = New Foo With {.Bar = "asdf", .Nan = "zxcv", .Tucket = "qwer"}
    Dim actualFoo = New Foo With {.Bar = "qwer", .Nan = "zxcv", .Tucket = "qwer"}

    AssertEquality(expectedFoo, actualFoo, "Bar")

End Sub
John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • the first argument of `GetValue()` can only be Integer or Long according to my compiler. Where `expected` is of type t (or Foo at runtime) – theB3RV Aug 01 '14 at 19:41
  • also, expected is of type Foo, expected_prop is a list of the properties of Foo, therefore `expected_prop.GetValue(expected)` makes 0 sense... – theB3RV Aug 01 '14 at 19:45
1

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