What are anonymous types in C#?

Özkan ARDİL
7 min readNov 2, 2023

--

Anonymous types in C#

Anonymous types in C# are nameless types that allow you to bundle a set of read-only properties into a single object without the need to explicitly define a type beforehand.

To create an anonymous object, you can use the ‘new’ keyword and specify the desired properties within curly braces. Here, we’ve created an anonymous type with three properties: ‘Name’ of type string, ‘State’ of type string, and ‘Age’ of type int.

var employee = new { Name = "Jack", State = "Boston", Age = 43 };

Console.WriteLine($"This person's name is {employee.Name}, he lives in {employee.State} and is {employee.Age} years old.");
The result of the code

The properties of anonymous types are read-only, meaning you cannot modify them in your code:

Anonymous types are read-only

Let’s consider a simple coding challenge to gain a better understanding of what anonymous types can be used for.

First, we define a class for ‘Pet’:

 internal class Pet
{
public string Name { get; set; }
public PetTypes Type { get; set; }
public int Age { get; set; }

public Pet(string name, PetTypes type, int age)
{
Name = name;
Type = type;
Age = age;
}
}

Then, we define an enum for ‘PetType’:

 internal enum PetTypes
{
Dog,
Cat
}

Next, we create a collection of ‘Pets’:

var pets = new[]
{
new Pet("Hannibal", PetTypes.Dog, 12),
new Pet("Black", PetTypes.Cat, 8),
new Pet("White", PetTypes.Dog, 4),
new Pet("Red", PetTypes.Dog, 7),
new Pet("Pink", PetTypes.Dog, 7),
new Pet("Brown", PetTypes.Dog, 7)
};

Each Pet has a name, type, and age.

What we want to do is to build a collection of strings that will contain data about each pet type and average age for pets of selected type.

We will use LINQ to do it. We need to group those pets by type and then, for each of the groups, we can calculate the average age:

var averageWeightsData = pets
.GroupBy(pet => pet.Type)
.Select(grouping => grouping.Average(pet => pet.Age));



foreach (var item in averageWeightsData)
{
Console.WriteLine(item);
}

This is what I want, but there is one problem.

Average ages of each type

We’ve only selected the average age of each group, losing the information about the name of each group.

I want to show the pet type and average age.

What should I do now?

To display both the pet type and average age, creating a class, struct, or record would be a possible solution.

However, it might be an overkill for this specific scenario.

I will create a new class for this very specific piece of data. It’s possible that I won’t ever use it in a different context.

So, there must be a better solution for that.

At this point, again anonymous types come to the stage.

Let’s continue to read…

The answer is to make use of an anonymous type.

An anonymous type is a type that is defined exactly where it’s needed, without even giving it a name.

It’s perfect for use cases like ours — where the type is small and temporary, and we don’t intend to use it anywhere else. So let’s modify the code according to our need.

var averageWeightsData = pets
.GroupBy(pet => pet.Type)
.Select(grouping => new
{
Type = grouping.Key,
AgeAverage = grouping.Average(pet=>pet.Age)
})
.OrderBy(data => data.AgeAverage);


foreach (var item in averageWeightsData)
{
Console.WriteLine($"Average age for type {item.Type} is {item.AgeAverage}");
}

The result od the modified code is shown below.

The result of the modified code

By using anonymous type within our code we reached the desired result.

How Can I Use an Anonymous Type In Different Code?

In our case, as you can see the anonymous type does not have a name. So, it is not possible for us to use it anywhere else.

How could we refer to it if we don’t know its name?

Actually, the compiler gives it a name that can be seen in the Common Intermediate Language, but even if we use the decompiler to find it, it won’t be possible to use it.

Just to satisfy your curiosity, I checked how the compiler named this particular type:

The name of the anonymoys type given by the Common Intermediate Language

The name of the anonymous type is at the top. As you can see it’s not very readable. Please note that from the perspective of Common Language Runtime anonymous types are no different than any other types.

Anonymous types have a few crucial characteristics:

  • They contain only read-only properties,
  • No other kinds of class members, such as methods or events, are valid
  • If no names are given to the properties of the anonymous type, the compiler will use the name of the property that was used to set the value of the anonymous type’s property.
  • Anonymous types are class objects, derived directly from System.Object.
  • They can’t be cast to any other type.
  • They override the Equals and GetHashCode methods to support value-based equality. Two anonymous objects with the same values will have the same hashcodes, and the Equals method will return true for them. Please note that the == operator is not overloaded, so it will return false (because they differ by reference).
  • They support non-destructive mutation with the “with” keyword. Remember: non-destructive mutation is not changing the original object, but rather creating a new one with changed values. Please check the sample code below.
var someData = new { number = 5, text = "My name is Ozkan'" };
var changedData = someData with { number = 10 };

Console.WriteLine($"SomeData values: number = {someData.number}, text = {someData.text}) \n");
Console.WriteLine($"ChangedData values: number = {changedData.number}, text = {changedData.text})");

The result of the code is:

Can we modify the value of an anonymous type property?

No. All properties of anonymous types are read-only.

When should we, and when should we not use anonymous types?

The best use case for anonymous types is when the type we want to use is simple and local to some specific context and it will not be used anywhere else. It’s very often used as a temporary object in complex LINQ queries. If the type is complex or we want to reuse it, it should not be anonymous. Also, anonymous types can only provide read-only properties; they can’t have methods, fields, events, etc, so if we need any of those features the anonymous types will not work for us.

Are anonymous types value or reference types?

They are reference types since they are classes, but they support value-based Equality with the Equals method. In other words, two anonymous objects with the same values of properties will be considered equal by the Equals method even if their references are different.

Source Code

You can access the source code of the project on my GitHub account. If you can give the repository a star and share the article, you will support me in reaching more people.

👏 If you found the content useful, I would appreciate it if you could support it with applause (you can also contribute with more than one applause by holding down the clap button for a long time).

⬇️ Check out my other articles.

💬 Let me know in the comment section what have I missed? Where I was wrong?

👨‍👦‍👦 You can also share this article with your friend. Argue a little on it. It is known that the truth is born in a dispute.

🙃 Stay determined, stay focused, and keep going

Thanks for reading…

--

--

Özkan ARDİL

.NET C# JS and Angular dev with 8+ yrs exp, self-taught & passionate web developer. Sharing tips & experiences in C# and web dev.