Target-Typed new in C#

Vaibhav • September 11, 2025

In previous chapters, we’ve written many object initializations using the familiar new keyword followed by the type name. For example, when creating a list, we’d write List<string> names = new List<string>();. This works well, but it can feel repetitive - especially when the type is already clear from the context. Starting with C# 9.0, the language introduced target-typed new, a feature that lets you omit the type on the right-hand side when it’s already known from the left.

In this article, we’ll explore what target-typed new is, how it simplifies object creation, when to use it, and how it fits into modern C# design. We’ll also look at how it interacts with generics, constructors, and type inference - all concepts you’ve already seen in earlier chapters.

What Is Target-Typed new?

Target-typed new allows you to omit the type name when creating an object, as long as the compiler can infer it from the context. For example:

// Traditional syntax
List<string> fruits = new List<string>();

// Target-typed new
List<string> fruits = new();

Both lines do the same thing - they create a new list of strings. But the second version is shorter and cleaner. The compiler knows the type from the left-hand side, so there’s no need to repeat it.

Target-typed new works only when the type is clear from the assignment context. If the compiler can’t infer the type, you’ll get an error.

Why Use Target-Typed new?

This feature is all about reducing redundancy. In modern C#, we often work with generic types, long type names, and complex initializations. Repeating the type name can clutter your code and distract from the logic. Target-typed new helps by:

  • Making code more concise
  • Improving readability
  • Reducing duplication
  • Aligning with other modern features like type inference and records

It’s especially useful in scenarios where the type is obvious - like variable declarations, field initializations, and property assignments.

Examples with Collections

Let’s revisit some examples from our earlier article on lists. Instead of writing:

List<int> numbers = new List<int>();

You can now write:

List<int> numbers = new();

The compiler sees that numbers is a List<int>, so it knows what type to create. You can also use initializer syntax:

List<char> vowels = new() { 'a', 'e', 'i', 'o', 'u' };

This creates a list of characters with five elements. The syntax is clean, expressive, and easy to read.

Using with Custom Types

Target-typed new works with your own classes too. Suppose you have a class:

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

You can create a new instance like this:

Person p = new() { Name = "Vaibhav", Age = 30 };

This is equivalent to new Person { ... }, but without repeating the type name. It’s especially helpful when working with DTOs, models, and configuration objects.

Constructor Overloads and Parameters

Target-typed new works with constructors that take parameters. For example:

class Product
{
    public string Name { get; }
    public decimal Price { get; }

    public Product(string name, decimal price)
    {
        Name = name;
        Price = price;
    }
}

You can create a product like this:

Product item = new("Laptop", 999.99m);

The compiler knows that item is a Product, so it uses the appropriate constructor. This works with any constructor overload - as long as the parameters match.

Note: If the constructor parameters are ambiguous, the compiler may not be able to resolve the correct overload. In such cases, you may need to specify the type explicitly.

Using with Records

In the previous article, we introduced records - a concise way to define immutable data types. Target-typed new works beautifully with records:

record Person(string Name, int Age);

Person p = new("Vaibhav", 30);

This creates a new record with the specified values. It’s clean, expressive, and aligns with the design goals of records - simplicity and clarity.

Working with Interfaces and Base Types

Target-typed new also works when assigning to an interface or base type. For example:

IList<string> names = new List<string>();

You can simplify this to:

IList<string> names = new();

The compiler sees that names is an IList<string>, and infers that you want to create a List<string>. This works as long as the right-hand type is compatible with the left-hand target.

Using with Fields and Properties

You can use target-typed new in fields and properties too. For example:

class Settings
{
    public Dictionary<string, string> Options { get; set; } = new();
}

This initializes the Options property with an empty dictionary. It’s concise and avoids repeating the type name.

Limitations and Edge Cases

While target-typed new is powerful, it has some limitations:

  • It only works when the type is clear from the context.
  • It doesn’t work with var - because var itself relies on type inference.
  • It may cause ambiguity with overloaded constructors or generic types.
  • It doesn’t work in method return statements - unless the return type is explicitly declared.

These limitations are minor, but it’s important to understand them - especially when designing APIs or working with complex types.

Target-typed new is part of a broader effort to make C# more expressive and less verbose - alongside features like records, init-only properties, and pattern matching.

Common Mistakes and How to Avoid Them

Here are a few common mistakes developers make with target-typed new:

  • Using it with var - which causes a compiler error.
  • Using it when the type is not clear - which leads to ambiguity.
  • Assuming it works in all contexts - it doesn’t work in lambda expressions or anonymous methods.
  • Mixing it with dynamic types - which breaks type inference.

These mistakes are easy to avoid once you understand how the compiler infers types.

Design Tips for Using Target-Typed new

Target-typed new is a design tool. Use it to make your code cleaner and more expressive:

  • Use it when the type is obvious and already declared.
  • Avoid it when the type is complex or ambiguous.
  • Use it with records, collections, and DTOs for clarity.
  • Combine it with object initializers for clean setup.

These tips help you write modern, maintainable C# code - whether you’re building a small utility or a large application.

Summary

Target-typed new is a modern feature in C# that simplifies object creation by removing redundant type declarations. You’ve learned how to use it with collections, custom types, records, interfaces, fields, and properties. You’ve also seen its limitations, common mistakes, and design tips.

By using target-typed new, you make your code cleaner, more readable, and more aligned with modern C# design. In the next article, we’ll explore Extension Methods - a powerful way to add functionality to existing types without modifying them.