C# 9.0: Target-typed New Expressions – Make Your Initialization Code Less Verbose

In the previous blog posts you learned about different C# 9.0 features:

In this blog post, let’s look at another very interesting feature of C# 9.0 that is called target-typed new expressions.

Target-typed means that an expression gets the type from the context it is used in. With C# 9.0 the new expression gets the type from the context, which means you don’t have to specify the target-type explicitly to call a constructor. Let’s look at this with a simple example.

Creating New Objects Before C# 9.0

Let’s define the Friend class that you see in the code snippet below. As you can see, it has a default constructor and also a constructor with the parameters firstName and lastName to initialize the properties FirstName and LastName.

public class Friend
{
    public Friend() { }

    public Friend(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

To create a new instance of this Friend class, you can use this statement:

Friend friend = new Friend();

You can also use the constructor overload to pass in a firstname and a lastname:

Friend friend = new Friend("Thomas", "Huber");

As the variable gets initialized directly with a new Friend, you can also use the var keyword for the variable declaration like below. The C# compiler detects in this case the type Friend for the variable, as you assign a new Friend instance to it. The var keyword was introduced in 2007 with C# 3.0 and .NET Framework 3.5, and it works for local variables.

var friend = new Friend("Thomas", "Huber");

Now, in all those cases above you can see that the new expression – that’s the part on the right side of the = sign – always requires the class name. That’s not the case anymore with C# 9.0 if the target-type is already known from the left side of the = sign, which is always the case if you don’t use the var keyword on the left side of the = sign.

Use Your First Target-typed New Expression

With C# 9.0 you can create a new Friend like below with the target-typed new expression to call the default constructor. Note that I don’t specify the Friend class on the right side of the = sign, the compiler gets it from the left side of the = sign:

Friend friend = new();

You can also call the overloaded constructor of the Friend class by passing in a firstname and a lastname:

Friend friend = new("Thomas", "Huber");

But, of course, you can not use the target-typed new expression when you use the var keyword to declare your variable, because then the compiler does not have a chance to find out the type that you want to create. So, the following statement does not work:

var friend = new("Thomas", "Huber"); // does NOT work

What About Optional Constructor Parameters?

You could define the Friend class also with optional constructor parameters like below:

public class Friend
{
    public Friend(string firstName = null, string lastName = null)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Calling that constructor with the target-typed new expression works exactly the same way as you would call it with a classic new expression, you just omit the class name on the right side of the = sign. You could call the constructor for example without any arguments:

Friend friend = new();

You could call it with a firstname:

Friend friend = new("Thomas");

You could call it with firstname and lastname:

Friend friend = new("Thomas", "Huber");

You could also use named arguments to call it with just a lastname:

Friend friend = new(lastName: "Thomas");

So, everything works the same way as before, you just omit the type after the new keyword.

What’s the Point When You Can Use Var?

You might ask yourself what’s the point of target-typed new expressions when you can use the var keyword? What is the advantage of this:

Friend friend = new("Thomas", "Huber");

over this:

var friend = new Friend("Thomas", "Huber");

With the target-typed new expression you omit the type on the right side of the = sign, with the var keyword you omit the type on the left side of the = sign. For both statements above, the C# compiler produces exactly the same Intermediate Language code. So, it is your decision what you prefer. At least it is your decision for local variables, and so far we just talked about local variables.

Did you notice that the first code snippet in this section with the variable Friend friend could theoretically be a field of a class? The second code snippet could not be a field of a class, as fields do not support the var keyword. Fields are one example where target-typed new expressions are really powerful, because with fields you can not use the var keyword. And that’s the main point why and where you want to use target-typed new expressions:

You can use the var keyword only for local variables. That means target-typed new expressions are especially powerful to initialize properties and fields, because there the var keyword is not an option.

Let’s look at these cases where var is not an option in the next sections, because for all these cases target-typed new expressions make your code less verbose.

Initialize Properties With Target-typed New Expressions

Look at the class below. It’s a simple, but typical MainViewModel class that you could use in XAML-based apps, for example WPF or UWP/WinUI, when applying the Model-View-ViewModel pattern (MVVM). It has the properties AddFriendCommand and Friends, and both are initialized in the constructor with a classic new expression.

public class MainViewModel
{
    public MainViewModel()
    {
        AddFriendCommand = new DelegateCommand(AddFriendExecute);
        Friends = new ObservableCollection<Friend>();
    }

    public DelegateCommand AddFriendCommand { get; }

    public ObservableCollection<Friend> Friends { get; }

    private void AddFriendExecute()
    {
        Friends.Add(new Friend());
    }
}

You can change the code in the constructor to the code that you see below. As you can see, the class names for the initialization are not needed anymore.

Note that also the generic <Friend> argument for the ObservableCollection<Friend> is not needed with the target-typed new expression. So, you don’t write new<Friend>(), but just new().

public MainViewModel()
{
    AddFriendCommand = new(AddFriendExecute);
    Friends = new();
}

You could also initialize the Friends property directly like this – and if you ask me, yes, I think this is really beautiful code:

public ObservableCollection<Friend> Friends { get; } = new();

In addition to these adjustments, you can also create the new Friend object in the AddFriendExecute method with a target-typed new expression like this:

private void AddFriendExecute()
{
    Friends.Add(new());
}

With the changes applied, the MainViewModel class looks like this:

public class MainViewModel
{
    public MainViewModel()
    {
        AddFriendCommand = new(AddFriendExecute);
        Friends = new();
    }

    public DelegateCommand AddFriendCommand { get; }

    public ObservableCollection<Friend> Friends { get; }

    private void AddFriendExecute()
    {
        Friends.Add(new());
    }
}

Beside properties, another very useful case for target-typed new expressions are fields. Let’s look at fields in the next section.

Initialize Fields With Target-typed New Expressions

Below you see an ErrorViewModelBase class that contains some typical stuff that I created in several .NET projects. Note that the class is a simplified version that contains just enough to show you the power of target-typed new expressions. As you can see below, the class contains two new expressions. One to initialize the field _errorsByPropertyName, and another one to create a new List<string>.

public class ErrorViewModelBase
{
    protected readonly Dictionary<string, List<string>> _errorsByPropertyName
      = new Dictionary<string, List<string>>();

    public void AddError(string propertyName, string error)
    {
        if (!_errorsByPropertyName.ContainsKey(propertyName))
        {
            _errorsByPropertyName[propertyName] = new List<string>();
        }
        _errorsByPropertyName[propertyName].Add(error);
    }
}

With C# 9.0, you can replace those new expressions with target-typed new expressions like shown in the code snippet below. Especially the fact that you don’t have to write new Dictionary<string, List<string>>(), but just new() to initialize the field is very powerful. Dictionary<string, List<string>> is already used and visible in the field declaration, so why duplicate it with the initialization? A target-typed new expression helps you here to avoid that code duplication.

As mentioned, you can not use the var keyword for fields, so using var is not an option here for the _errorsByPropertyName field.

public class ErrorViewModelBase
{
    protected readonly Dictionary<string, List<string>> _errorsByPropertyName = new();

    public void AddError(string propertyName, string error)
    {
        if (!_errorsByPropertyName.ContainsKey(propertyName))
        {
            _errorsByPropertyName[propertyName] = new();
        }
        _errorsByPropertyName[propertyName].Add(error);
    }
}

Also the creation of a List<string> in the AddError method with just new() instead of new List<string>() is nice. With these changes, I think this class looks much cleaner and less verbose than before.

When to Use Target-typed New Expressions

There are many cases where I’ll definitely use target-typed new expressions without a thought. These are the cases where it is obvious to any programmer what new() will create. For example, look at this property declaration and initialization:

public ObservableCollection<Friend> Friends { get; } = new ObservableCollection<Friend>();

Here you can use a target-typed new expression without any thought, because it is totally clear from the property declaration that new() will create an ObservableCollection<Friend>:

public ObservableCollection<Friend> Friends { get; } = new();

But when you look at the constructor of the MainViewModel class in the code snippet below, you can not say what the target-typed new expressions create by just looking at the constructor:

public MainViewModel()
{
    AddFriendCommand = new(AddFriendExecute);
    Friends = new();
}

When reading the code, you need to look at the types of the properties AddFriendCommand and Friends to know what the two new expressions in the code snippet above are actually creating. But that’s only true if you do not read the code in a tool like Visual Studio, but in a simple text editor or on a blog like this one. If you look at the code in Visual Studio, you can hover any target-typed new expression with your mouse to see which constructor it calls. In the screenshot below I hovered the second new expression in Visual Studio and you can see in the tooltip that it actually creates an ObservableCollection<Friend>.

You can even navigate to the called constructor. In Visual Studio you do this by pressing F12 when the cursor is on the target-typed new expression. So, with this tooling support, the use of target-typed new expressions seems to be ok in any case.

Summary

You saw in this blog post different use cases for target-typed new expressions. I have to admit, I’m already a big fan of target-typed new expressions. Especially for direct field and property initialization where the var keyword is not an option, a target-typed new expression leads to much nicer code.

In the next blog post, you will learn more about the improved pattern matching in C# 9.0.

Happy coding,
Thomas

Share this post

Comments (24)

  • Avi Farah Reply

    Thank you

    September 10, 2020 at 6:00 am
    • Thomas Claudius Huber Reply

      You’re welcome Avi. And thank you, love it that you took the time to write this comment!

      September 10, 2020 at 5:54 pm
  • Gordon Reply

    As I was reading through your article I wasn’t really sure of the value that a “target-typed new” gives, but the very last graphic was my “aha!” moment. Without the IDE tool-tip the code describes what is happening in terms of the domain. It is not cluttered with the technical implementation details. If I’m interested in the technical implementation, then I can use the information in the tool-tip. The intent of the code is front and centre, with no distractions (as long as we name things nicely, but that’s a different topic altogether :-) ). Thanks for taking the time to post this. I found it enlightening.

    September 10, 2020 at 8:03 pm
    • Thomas Claudius Huber Reply

      Hey Gordon, thank you! I’m happy to read that you like the article. And I agree to what you wrote about this new syntax.

      September 11, 2020 at 9:46 am
  • thelazydogsback Reply

    This seems like exactly the wrong way to go — you want to omit “new”, not the type.
    var friend = Friend();

    This is what F# and many other languages do. This is especially important for more complex, nested expressions.
    With “news” everywhere, it’s a mess.

    var ast = Expr(Plus(1,Minus(4,3),Call(‘foo’,’x’,Plus(‘y’,’z’)));

    To do this in C#, you’d need to manually create a static helper function to do construction.

    September 10, 2020 at 8:54 pm
    • Thomas Claudius Huber Reply

      The var keyword does not work for fields and properties, it only works for local variables. Which means in other words that all of the options that you’ve mentioned work only for local variables. :-) I hope this makes it a bit clearer that this new syntax is an improvement.

      September 11, 2020 at 9:45 am
      • Vitali Reply

        All things before was good, but this is not. Please don’t use it in practice. Painful

        September 30, 2020 at 11:51 pm
  • Martin Nielsen Reply

    Awesome intro to Target-typed New Expressions.
    I’m especially looking forward to this feature, so I only have to write the declaration of complex generic types once :D
    Also populating lists will become a bit less verbose when we can omit the type.

    Keep up providing awesome content :thumbsup:

    September 11, 2020 at 6:29 am
    • Thomas Claudius Huber Reply

      Thank you Martin. Yes, absolutely, I’m also looking forward to this feature, I think it can simplify a lot of code. Especially for generic types like you mentioned.

      September 11, 2020 at 9:42 am
  • Wan-Sik Choi Reply

    Very much helpfull to improve C# knowledge!

    September 11, 2020 at 7:39 am
  • Richard Bushnell Reply

    Good article Thomas. Nicely explained.

    I’m not sure I entirely agree that it makes for beautiful code. As you know, I’ve been doing C# a long time and this is all starting to look a bit confusing to me. Doesn’t it to you?

    For me, there’s no such thing as beautiful code per se; there are only coders who can or can’t type quickly, and code that’s easy to understand when we come back to maintain it later. Sure, missing out the names of types in initialisations makes it easier to type in the first place, but I doubt I’d be able to understand any of this code later without doing a double-take.

    As an example, yesterday I had to read nearly 2000 lines of java to fix a bug. The fix only required a single line, but if I’d have had to go back and forth in the code to work out exactly what objects were being added where (or worse – if I’d had to set up an environment to build the thing just to get compiler hints), it would’ve take me 5 times as long to find where that single line was required, which in itself took 30 seconds to write.

    It seems that “features” such as this look great to developers who maybe haven’t had to read much code back yet, but those of us who have, we know the benefit in being able to understand code without requiring tools. And adding more and more syntax to a language for the sole purpose of keeping up with the competition means I’ll have to learn more and more rules to keep being able to understand it.

    I’m not against progress, but my question is if this is actually progress or not.

    Wouldn’t you agree?

    September 11, 2020 at 11:25 am
    • Thomas Claudius Huber Reply

      Hey Richard, thank you, happy to read that a pro like you likes the article. :)

      Yes, with all the new features the language gets harder to read, as there are many options. I agree to this, the vocabulary gets bigger.

      Regarding “beautiful code”, it depends how we interpret it. When I say beautiful code, I don’t think about the numbers of characters that I type. I think more and maybe only about readability and maintainability. Sometimes we can make code super compact by using generic features, but often it gets more complicated. Simplicity is key.

      For the target-typed new expressions I think direct field and property initializations make it clear what they do. At other places they’re a bit more magic, and I agree that this can make the code harder to read. It’s a bit similar to the var keyword. When it was introduced, some developers used it only when the class name was obvious from the code on the right side of the equals sign. Today most devs use it everywhere they can. Because I think in the end it is one thing that makes code really readable: Good names.

      For example:
      person = new();

      is better than

      p = new();

      But we will see how things evolve in the future. We have to work with it. I think it’s progress, but I agree to your comment.

      Have a wonderful weekend Richard, made me happy to read here from you!
      Thomas

      September 11, 2020 at 2:36 pm
  • Avi Farah Reply

    Thank you sir. Great article

    September 11, 2020 at 1:20 pm
  • Brian Parkinson Reply

    Hi

    C# appears to be moving closer to VB.Net every day.
    Cannot understand why Functions in C# and VB cannot be included in same Class as both language are effectively the same. Heresy to C and C++ devotees. IDE for both languages could easily be tweeked to recognise the difference in code identical except for declarations. Example:
    C# public class Friend
    {
    public Friend() { }
    public Friend(string firstName, string lastName)
    {
    FirstName = firstName;
    LastName = lastName;
    }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    }

    VB
    public class Friend
    public sub New
    ‘Default constructor
    end sub ‘substitute for {
    public sub New(firstName as string , lastName as string )
    FirstName = firstName
    LastName = lastName
    end sub ‘substitute for }
    public Property FirstName as string
    public Property LastName as string
    end class

    September 12, 2020 at 5:50 am
    • Thomas Claudius Huber Reply

      What you’re saying is that you want to mix C# and VB.NET in a single source file? That’s not planned, and it would be very hard, as there are different compilers for the different .NET languages like C#, VB.NET and F#.

      September 12, 2020 at 9:28 am
  • James Lonero Reply

    Thank you, Thomas, for a peek forward at C# 9. The first part about removing “var “ will save keystrokes for the programmer. That will be a help as any programmer can attest. Initializing properties and internal class data using “new()” alone is also a keystroke saver.

    But if we are going to make it so easy to initialize properties and class data, will C# 10 automatically initialize our properties and fields for us as we instantiate the class? (That sounds like something an earlier version of basic did.) Of course, if this is the case, then we will have to explicitly set the fields to null if we want them initialized to null.

    September 13, 2020 at 8:20 pm
    • Thomas Claudius Huber Reply

      Hey James, that’s a great question regarding C# 10 and automatically initialized fields and properties. I haven’t heard and read anything about this, and I don’t know if this is going to happen.

      September 14, 2020 at 11:18 am
  • sharpdoctor Reply

    I think in the code snippet after
    “With the changes applied, the MainViewModel class looks like this:”

    you have still
    public ObservableCollection Friends { get; }

    but it should be:
    public ObservableCollection Friends { get; } = new();

    and remove the intitialization code
    Friends = new();
    from the constructor

    It’s perfectly valid code but applying these changes will better illustrate this feature.

    September 15, 2020 at 11:57 am
    • Thomas Claudius Huber Reply

      Hey sharpdoctor, thank you for the feedback. No, I think it’s correct as it is, as I had the original initialization code also in the constructor, so I also wanted to keep it there with target-typed new expressions, so that you can see exactly the same class structure with this new feature. As I wrote, you could initialize the property directly with new(), but that would be the alternative way to this:

      public ObservableCollection<Friend> get; } = new ObservableCollection<Friend>();

      And I hadn’t this in the original class. I hope this makes it clear what my thoughts were there. :)

      Happy coding,
      Thomas

      September 15, 2020 at 3:18 pm
  • Ingo Reply

    Interesting. And if it leads to better naming, everything is fine. Thank you Sir! ;)

    September 18, 2020 at 1:30 pm

Leave a Reply to Thomas Claudius Huber Cancel reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.