Record Types, Init-Only Properties, Top-Level Programs, With Expressions, Enhanced Pattern Matching, and Covariant Returns.

 

1. Record Types

Record types were introduced in C# 9.0 as a way to create immutable types with built-in support for value-based equality. Records are particularly useful for defining simple data structures where immutability and equality based on the value of properties (rather than reference) are desired.

Example: Record Types

public record Person(string FirstName, string LastName); class Program { static void Main() { var person1 = new Person("John", "Doe"); var person2 = new Person("John", "Doe"); Console.WriteLine(person1 == person2); // Output: True (value-based equality) Console.WriteLine(person1); // Output: Person { FirstName = John, LastName = Doe } } }
  • Explanation: In this example, Person is a record type with two properties, FirstName and LastName. The equality comparison (==) checks the values of these properties, not their references. The default ToString method also provides a string representation of the record's values.

2. Init-Only Properties

Init-only properties, introduced in C# 9.0, allow you to create properties that can only be set during object initialization. This ensures that the property values remain immutable after the object is constructed.

Example: Init-Only Properties

public class Car { public string Make { get; init; } public string Model { get; init; } } class Program { static void Main() { var car = new Car { Make = "Toyota", Model = "Corolla" }; // car.Make = "Honda"; // Error: Cannot modify an init-only property Console.WriteLine($"{car.Make} {car.Model}"); // Output: Toyota Corolla } }
  • Explanation: The Car class has Make and Model properties that are init-only. They can only be set during initialization and are immutable afterward.

3. Top-Level Programs

Top-level programs, introduced in C# 9.0, simplify the entry point of a console application by allowing you to omit the Main method and directly write code at the top level.

Example: Top-Level Programs

using System; Console.WriteLine("Hello, World!");
  • Explanation: In this example, there’s no Main method. The Console.WriteLine statement is at the top level, and the compiler automatically generates the Main method behind the scenes. This is particularly useful for small or simple programs.

4. With Expressions

With expressions in C# 9.0 allow you to create a copy of an object with modifications to some of its properties. This is particularly useful for records and immutable types.

Example: With Expressions

public record Person(string FirstName, string LastName); class Program { static void Main() { var person1 = new Person("John", "Doe"); var person2 = person1 with { LastName = "Smith" }; Console.WriteLine(person1); // Output: Person { FirstName = John, LastName = Doe } Console.WriteLine(person2); // Output: Person { FirstName = John, LastName = Smith } } }
  • Explanation: The with expression creates a new Person object, person2, by copying person1 and modifying the LastName property. The original person1 remains unchanged.

5. Enhanced Pattern Matching

C# 9.0 introduces enhancements to pattern matching, including new patterns such as relational patterns, logical patterns, and more. These patterns make it easier to express complex conditions in a concise manner.

Example: Enhanced Pattern Matching

class Program { static string ClassifyNumber(int number) => number switch { < 0 => "Negative", 0 => "Zero", > 0 and <= 10 => "Small Positive", > 10 => "Large Positive", _ => "Unknown" }; static void Main() { Console.WriteLine(ClassifyNumber(-5)); // Output: Negative Console.WriteLine(ClassifyNumber(5)); // Output: Small Positive Console.WriteLine(ClassifyNumber(15)); // Output: Large Positive } }
  • Explanation: This example uses relational patterns (< 0, > 0 and <= 10) and logical patterns (and) to classify a number. The enhanced pattern matching makes the switch expression more expressive and readable.

6. Covariant Returns

Covariant returns, introduced in C# 9.0, allow an overriding method to return a more derived type than the method it overrides. This provides more flexibility and type safety in object-oriented design.

Example: Covariant Returns

public class Animal { public virtual Animal GetAnimal() => new Animal(); } public class Dog : Animal { public override Dog GetAnimal() => new Dog(); // Covariant return } class Program { static void Main() { Dog dog = new Dog(); Animal animal = dog.GetAnimal(); // This returns a Dog, but can be assigned to an Animal variable Console.WriteLine(animal.GetType().Name); // Output: Dog } }
  • Explanation: The Dog class overrides the GetAnimal method of the Animal class and returns a more derived type (Dog). This is an example of covariant return types, where the overridden method can return a more specific type than the base method.

Summary

  1. Record Types: Introduce immutable types with value-based equality, making it easier to work with data-centric objects that should not change after creation.
  2. Init-Only Properties: Allow properties to be set only during object initialization, ensuring that they remain immutable afterward.
  3. Top-Level Programs: Simplify the syntax for small programs by allowing code to be written directly at the top level, without the need for a Main method.
  4. With Expressions: Enable the creation of new objects by copying existing ones and modifying specific properties, particularly useful for immutable types.
  5. Enhanced Pattern Matching: Extend pattern matching capabilities with relational and logical patterns, making it easier to express complex conditions concisely.
  6. Covariant Returns: Allow overriding methods to return more derived types, providing more flexibility in method return types while maintaining type safety.

Post a Comment