.NET Tips and Tricks

Blog archive

Comparing Anonymous Objects in C# and VB

Trust me: There's actually a tip at the end of this column, but it's going to take me awhile to get there. Be patient -- I do have a point and I am getting to it.

When it comes to comparing objects, what .NET considers the same isn't what normal human beings consider the same. Consider this code that creates two Customer objects, both representing Customer A123:

Dim cust1 As New Customer("A123")
Dim cust2 as Customer
cust2 = cust1

In VB, if I try to compare the two objects using this syntax, I get a compile time error:

If cust1 = cust2 Then

I can, however, use this syntax and the result, unsurprisingly, is True:

If cust1.Equals(cust2) Then

The test is true, however, only because the variable cust1 is pointing at the same object as the variable cust2. The .NET documentation refers to this as "reference equality." If, however, I create two separate objects, as this code does, and compare cust1 and cust2, the test returns false:

Dim cust1 As New Customer("A123")
Dim cust2 As New Customer("A123")
If cust1.Equals(cust2) Then

The test fails because the cust1 variable is pointing at a different object than cust2, even though the two objects, presumably, represent exactly the same customer entity and have identical values in all of their properties.

We, as human beings, might consider these objects to be "the same" because the objects represent the same data -- that's called "value equality" -- but we're not .NET. C# gives the same results as VB, but is willing to accept the x == y syntax.

Anonymous and Different
.NET uses object equality for most objects, but there are exceptions. For scalar variables and strings, for instance, .NET uses value equality. As a result, this test is true:

Dim num1 As Integer = 2
Dim num2 As Integer = 2
If num1 = num2 Then

Things are also different if you use anonymous objects -- but only if you're using C#. In C#, you might create two anonymous objects like this:

var x = new {  id = "A123", 
    CompanyName = "PH&V Information Services" };
var y = new {  id = "A123", 
    CompanyName = "PH&V Information Services" };

In C#, this test is false:

if (x == y)

But this test is true:

if (x.Equals(y))

For anonymous objects and with the Equals method, C# stops using reference equality and starts using value equality: C# compares the value of properties with identical signatures (names and types). But wait! It gets worse. In VB, the anonymous objects look like this:

Dim x = New With {.id = "A123", 
    .CompanyName = "PH&V Information Services"}
Dim y = New With {.id = "A123", 
    .CompanyName = "PH&V Information Services"}

The x = y syntax is still an error but this test, which looks just like the C# test, gives the same answer as with "un-anonymous objects" and remains false:

If x.Equals(y) Then

So, unlike C#, VB continues to use reference equality with anonymous objects.

Listen: It's not my fault.

The Tip (Finally)
This is, of course, an accident waiting to happen. The good news is that you can fix this difference in behavior (and, by "fix", I mean: get the almost identical behavior almost everywhere). As a bonus, it simplifies your VB code when you do want to compare two anonymous objects: Just use the Key keyword to identify to VB properties to be used when comparing anonymous objects. Using Key causes VB to switch to using value equality when comparing anonymous objects, just like C#.

This example flags just the id property in my anonymous object as providing the value to be used when comparing this anonymous object with another anonymous object:

Dim x = New With {Key .id = "A123", CompanyName …
Dim y = New With {Key .id = "A123", CompanyName …

The x = y syntax is still a syntax error, but x.Equals(y) now returns the same result as the equivalent C# test: True. And, actually, VB's approach is more flexible than C#'s, as you can choose what counts as equality: all of the properties on the object or some arbitrary collection. One caveat: If you're comparing anonymous objects in either C# or VB, they must have identical sets of properties or the comparison automatically fails.

Of course, in C# x == y still returns a different result than x.Equals(y) for anonymous objects.

Hey: There's only so much I can do.

Posted by Peter Vogel on 06/25/2012


comments powered by Disqus

Featured

  • Full Stack Hands-On Development with .NET

    In the fast-paced realm of modern software development, proficiency across a full stack of technologies is not just beneficial, it's essential. Microsoft has an entire stack of open source development components in its .NET platform (formerly known as .NET Core) that can be used to build an end-to-end set of applications.

  • .NET-Centric Uno Platform Debuts 'Single Project' for 9 Targets

    "We've reduced the complexity of project files and eliminated the need for explicit NuGet package references, separate project libraries, or 'shared' projects."

  • Creating Reactive Applications in .NET

    In modern applications, data is being retrieved in asynchronous, real-time streams, as traditional pull requests where the clients asks for data from the server are becoming a thing of the past.

  • AI for GitHub Collaboration? Maybe Not So Much

    No doubt GitHub Copilot has been a boon for developers, but AI might not be the best tool for collaboration, according to developers weighing in on a recent social media post from the GitHub team.

  • Visual Studio 2022 Getting VS Code 'Command Palette' Equivalent

    As any Visual Studio Code user knows, the editor's command palette is a powerful tool for getting things done quickly, without having to navigate through menus and dialogs. Now, we learn how an equivalent is coming for Microsoft's flagship Visual Studio IDE, invoked by the same familiar Ctrl+Shift+P keyboard shortcut.

Subscribe on YouTube