Learn two of the most important features in C# 9.0 to make your code more concise, readable, flexible, and efficient. Credit: Thinkstock C# 9 introduced a number of features that allow us to write more efficient and flexible code. In previous articles we examined record types, static anonymous functions, relational and logical patterns, and top-level programs. In this article we’ll look at two more useful features in C# 9 — new target typing capabilities and covariant returns. Target typing refers to using an expression that gets its type from the context in which it is used, rather than specifying the type explicitly. With C# 9, target typing now can be used in new expressions and with conditional operators. Support for covariant return types in C# 9 allows the override of a method to declare a “more derived” (i.e., more specific) return type than the method it overrides. To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here. C# 9.0 is available in Visual Studio 2019 16.9 Preview 1 or later, or in the .NET 5.0 SDK. Create a console application project in Visual Studio First off, let’s create a .NET Core console application project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new .NET Core console application project in Visual Studio. Launch the Visual Studio IDE. Click on “Create new project.” In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed. Click Next. In the “Configure your new project” window, specify the name and location for the new project. Click Create. We’ll use this .NET Core console application project to work with target typing and covariant returns in the subsequent sections of this article. Use target typing with new expressions in C# 9 With C# 9 you now have improved support for target typing. There are two new ways in which you can implement target typing — in new expressions and with conditional operators. When using target-typed new expressions, you need not mention the type you want to instantiate. Let’s understand this with an example. Consider the following class: public class Author { private int Id { get; set; } private string FirstName { get; set; } private string LastName { get; set; } public Author(int id, string firstName, string lastName) { Id = id; FirstName = firstName; LastName = lastName; } } The following code snippet illustrates how you can use target typing to omit specifying the type when creating an instance of the class shown above. static void Main(string[] args) { var authors = new List<Author> { new (1, "Joydip", "Kanjilal"), new (2, "Dean", "Jones"), new (3, "Steve", "Smith") }; Console.Read(); } Use target typing with conditional operators in C# 9 With C# 9 it is now possible to infer types using conditional operators. Consider the Person class given below: public class Person { private int Id { get; set; } private string FirstName { get; set; } private string LastName { get; set; } public Person(int id, string firstName, string lastName) { Id = id; FirstName = firstName; LastName = lastName; } } Assume that there are two types of workers — an employee and a consultant. Here are the two classes that represent an employee and a consultant: public class Employee : Person { private string Department { get; set; } public Employee(int id, string firstName, string lastName, string department) : base(id, firstName, lastName) { Department = department; } } public class Consultant : Person { private int RatePerHour { get; set; } public Consultant(int id, int ratePerHour, string firstName, string lastName) : base(id, firstName, lastName) { RatePerHour = ratePerHour; } } The following code will compile in C# 9, but will not compile in earlier versions of C#: Employee employee = new Employee(1, “Joydip”, “Kanjilal”, “Development”); Consultant consultant = new Consultant(1, 150, “Joydip”, “Kanjilal”); Person person = employee ?? consultant; //Compilation error prior to C# 9 C# 9 lets you use target-typed conditional operators in ternary statements. Use covariant return types in C# 9 Covariant return types is a feature that enables you to override a method of a base class with a method in the derived class to return a more specific type. Earlier versions of C# did not allow returning a different type (than its base version) in an overridden method of a derived class. This changes in C# 9. For example, suppose you have two classes A and B and that the latter extends the former. If you have a virtual or abstract method in class A, you can override it in class B. You can do this because the C# programming language provides support for run-time polymorphism or late binding. However, until C# 9, you could not change the return type of the overridden method in the derived class. Let’s understand this with an example. Consider the updated version of the Person class given below. public class Person { private int Id { get; set; } private string FirstName { get; set; } private string LastName { get; set; } public Person() { } public Person(int id, string firstName, string lastName) { Id = id; FirstName = firstName; LastName = lastName; } public virtual Person GetPerson() { return new Person(); } } Note we’ve added a virtual method and a default constructor. Here we are returning an instance of the Person class from the GetPerson method by calling the Person class’s default constructor. Now consider the Employee class given below: public class Employee : Person { private string Department { get; set; } public Employee() { } public Employee(int id, string firstName, string lastName, string department) : base(id, firstName, lastName) { Department = department; } public override Employee GetPerson() { return new Employee(); } } And we’ve added a default constructor here too. Here an instance of the Employee class is being returned by the GetPerson method that overrides the Employee class. Interestingly, the return type of the GetPerson method is Employee in the Employee class. Note that the above code would not compile in C# versions before C# 9 because you’re constrained to use the same signature for your overridden methods in a derived class. Covariance and contravariance are longtime C# features (added with C# 4.0) that provide a polymorphic extension to delegates, arrays, and generics. Covariance enables you to use a more derived type (more specific) than originally specified, while contravariance enables you to use a less derived type (less specific). You can learn more about covariance and contravariance from Microsoft’s online documentation. How to do more in C#: How to use top-level programs in C# 9 How to use pattern matching in C# How to work with read-only collections in C# How to work with static anonymous functions in C# 9 How to work with record types in C# How to use implicit and explicit operators in C# Singleton vs. static classes in C# How to log data to the Windows Event Log in C# How to use ArrayPool and MemoryPool in C# How to use the Buffer class in C# How to use HashSet in C# How to use named and optional parameters in C# How to benchmark C# code using BenchmarkDotNet How to use fluent interfaces and method chaining in C# How to unit test static methods in C# How to refactor God objects in C# How to use ValueTask in C# How to use immutability in C# How to use const, readonly, and static in C# How to use data annotations in C# How to work with GUIDs in C# 8 When to use an abstract class vs. interface in C# How to work with AutoMapper in C# Related content feature What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos