The C# compiler enables you to create a new type at runtime which is not available at the source code level. It encapsulates a set of read-only properties into a single object without having to first explicitly define a type. The type of the properties is inferred by the compiler which can create an anonymous type by using the properties in an object initializer.

For example, consider the following declaration:

var person = new { Name = "Mony Hamza", SSN = "12345678" };

Here, the compiler automatically creates an anonymous type and infers the types of the properties from the object initializer. It also creates the private fields associated with these properties and the necessary set and get accessors. When the object is instantiated, the properties are set to the values specified in the object initializer.

Here is an example for declaring an anonymous type and displaying its content:

I've received a question about why to use "implicitly typed variables". If you are to use an anonymous variable, then this variable must be initialized using the keyword var. We also have to consider the following notes about Anonymous types:

Anonymous types are reference types that derive directly from object. From the perspective of the common language runtime, an anonymous type is no different from any other reference types.

If two or more anonymous types have the same number and type of properties in the same order, the compiler treats them as the same type and they share the same compiler-generated type information.

An anonymous type has method scope. To pass an anonymous type, or a collection that contains anonymous types, outside a method boundary, you must first cast the type to object. However, this defeats the strong typing of the anonymous type. If you must store your query results or pass them outside the method boundary, consider using an ordinary named struct or cla<code>ss instead of an anonymous type.

Anonymous types cannot contain unsafe types as properties.

Because the Equals and GetHashCode methods on anonymous types are defined in terms of the Equals and GetHashcode of the properties, two instances of the same anonymous type are equal only if all their properties are equal.

Lambda expressions provide a concise syntax for writing anonymous methods that can contain expressions and statements, and can be used to create delegates. All lambda expressions use the lambda operator =>, which is read as "goes to". The left side of the lambda operator specifies the input parameters (if any) and the right side holds the expression or statement block. The lambda expression x => x * x is read "x goes to x times x."

Cross join:
A is matched to x
A is matched to y
A is matched to z
B is matched to x
B is matched to y
B is matched to z
C is matched to x
C is matched to y
C is matched to z
Filtered non-equijoin:
y is matched to A
y is matched to B
y is matched to C
z is matched to A
z is matched to B
z is matched to C

In the first query expression it selects the Upper, Lower so it matches each upper letter with all the lower ones. However, in the second filter example, it selects Lower, Upper so that it matches each lower letter with all the upper ones.

Using Group By

The group clause returns a sequence of IGrouping Of (TKey, TElement)) objects that contain zero or more items that match the key value for the group.

Names that start with the letter 'M':
Mony
Marica
Names that start with the letter 'H':
Hamza
Names that start with the letter 'J':
John
Names that start with the letter 'A':
Adam
Names that start with the letter 'O':
Olivia

Now let's add a little modification to the query in the previous example:

var NameGroups =
from name in Names
group name by name[0];
orderby name[0]

The result will be:

Names that start with the letter 'A':
Adam
Names that start with the letter 'H':
Hamza
Names that start with the letter 'J':
John
Names that start with the letter 'M':
Mony
Names that start with the letter 'O':
Olivia

Using into

It can be used to create a temporary identifier to store the results of a group, join or select clause into a new identifier. This identifier can itself be a generator for additional query commands.

The previous example will return each employee name and the department name.

Group Join

A join clause with an into expression is called a group join.

Left Outer Join

In a left outer join, all the elements in the left source sequence are returned, even if no matching elements are in the right sequence. To perform a left outer join, use the DefaultIfEmpty method in combination with a group join.

A partial class or struct may contain a partial method. One part of the class contains the signature of the method. An optional implementation may be defined in the same part or another part. If the implementation is not supplied, then the method and all calls to the method are removed at compile time.

Cool. I'm still reading through the article but noticed something which doesn't make sense to me. In the group by example, I don't understand how it would produce that output when the outer and inner loops are exactly the same?