Since it was introduced in VB.NET 2008, LINQ has become fundamental in VB.NET - but it's still widely misunderstood. This article is one of a series at About Visual Basic that covers the major ways to program LINQ. The goal is for a beginning Visual Basic .NET programmer to get up to speed on LINQ. If you found this article from a search and you would like to start at the beginning, you can find an introduction to the overall LINQ technology - what it covers and what you can do with it - in the article LINQ - An Example Driven Introduction with an example showing how LINQ could be used to start web pages using selections made with CheckBox controls. There is an index to all of the articles in the series in the beginning of the article.
In the Object Initializers article, here at About Visual Basic, I conclude the tip by showing how objects can be initialized as an anonymous type without even creating or naming a class. Here's the last code snippet. You might want to read that article again to fully understand this one.
Dim myEmp = New With
{.id = 12345,
.firstName = "Dan",
.lastName = "Mabbutt"}
This may look simple and easy to understand to you. That's good! But the compiler is actually doing a lot of work that versions of VB.NET before Framework 3.5/VB.NET 2008 didn't do. The compiler is actually creating, initializing, and using a variable in this statement that is never shown. And the correct type is inferred from assignment. The effect is the same as it would be if you declared a class in your code, but this code doesn't have a class. That's why it's called an anonymous type.
You might be curious about what the type actually is. You can ask VB.NET to display that information about that variable with a statement like this:
Console.WriteLine(myEmp.GetType)
This gives you this result in the Output window (the name may be different on your system):
VB$AnonymousType_0`3[System.Int32,System.String,System.String]
This tells you that the complex object consists of an Int32 and two Strings and it does have an internal name.
Along with anonymous types, another keyword - Key - has been introduced and has some very interesting behaviors. The purpose is to allow you to select exactly which variables in an anonymous type should be used in either the calculation of a hashcode (GetHashCode) or an equality comparison. Consider this code:
Dim myEmp1 = New With
{Key .id = 1,
Key .firstName = "Dan",
.lastName = "Mabbutt"}
Dim myEmp2 = New With
{Key .id = 1,
Key .firstName = "Dan",
.lastName = "Rabbit"}
Console.WriteLine(myEmp1.GetHashCode)
Console.WriteLine(myEmp2.GetHashCode)
Console.WriteLine(myEmp1.Equals(myEmp2))
The complete contents of the two objects, myEmp1 and myEmp2, are not actually equal. But since only the id and firstName are declared as part of the Key items, their hash code values are equal anyway and the Equals method returns True.
2108557749
2108557749
True
If the anonymous types were initialized from the result of a database query or perhaps a supplied parameter, the comparison wouldn't be so obvious, however. One big advantage of using the Key keyword and anonymous types is that you can select any grouping of the individual variables to include. But another advantage is that you can make this kind of comparison in the first place. If you try to use the Equals method without the Key parameter, it doesn't work. Consider this code:
Dim myEmpClass1 = New With
{.id = 1,
.firstName = "Dan",
.lastName = "Mabbutt"}
Dim myEmpClass2 = New With
{.id = 1,
.firstName = "Dan",
.lastName = "Mabbutt"}
Console.WriteLine(myEmpClass1.GetHashCode)
Console.WriteLine(myEmpClass2.GetHashCode)
Console.WriteLine(myEmpClass1.Equals(myEmpClass2))
In this case, the contents of the two objects are equal, but the result of running this code is:
32977404
7588182
False
Why? Microsoft's documentation for the Object.Equals(Object) method tells us:
"Equals supports reference equality for reference types ... reference equality means the object references that are compared refer to the same object."
Since they are both declared independentl, these are clearly different objects. The MSDN documentation offers the helpful suggestion that you can always override the method and code your own "value" equality test.
"For some kinds of objects, it is desirable to have Equals test for value equality instead of referential equality. Such implementations of Equals return true if the two objects have the same 'value', even if they are not the same instance. The type's implementer decides what constitutes an object's 'value'."
The use of anonymous types, and the Key parameter, makes that unnecessary.

