What's New in C# 7.3?
A look at the small but useful new features introduced in C# 7.3, including tuple equality, enum constraints, and performance improvements for working with `in` parameters.
While not a major version release, C# 7.3, which shipped in May 2018, brought a collection of small but welcome improvements to the language. These features continue the theme of making C# more convenient for everyday coding and enabling higher performance in low-level scenarios.
Let's look at some of the most useful additions in C# 7.3.
1. Tuple Equality
C# 7.0 introduced a powerful new syntax for creating and working with tuples. C# 7.3 enhances this by making tuples comparable with the ==
and !=
operators.
var tuple1 = (a: 1, b: 2);
var tuple2 = (a: 1, b: 2);
// In C# 7.3, this now works as you would expect.
if (tuple1 == tuple2)
{
Console.WriteLine("The tuples are equal."); // This will be printed
}
The comparison is done element by element, from left to right. This makes tuples even more useful for simple data structures and for returning multiple values from a method.
2. Enum Constraints in Generics
You can now specify System.Enum
as a constraint for a generic type parameter. This allows you to write generic utility methods that work with any enum type in a type-safe way.
// This method will only accept types that are enums.
public static string GetEnumName<T>(T value) where T : System.Enum
{
return Enum.GetName(typeof(T), value);
}
// Usage
string sunday = GetEnumName(DayOfWeek.Sunday);
3. in
Overload Resolution
C# 7.2 introduced the in
parameter modifier, which allows you to pass arguments by reference in a read-only manner, avoiding unnecessary copying of large structs. C# 7.3 improves how the compiler resolves method overloads with in
parameters, making it easier to work with them without ambiguity.
4. Expression Variables in More Places
C# 7.0 introduced out
variables, allowing you to declare a variable right at the point where it is passed as an out
argument. C# 7.3 expands where you can use these expression variables, such as in field initializers and query clauses.
Example in a constructor initializer:
public class MyClass
{
private int _value;
public MyClass(string s) : this(int.TryParse(s, out var i) ? i : 0)
{
}
public MyClass(int value)
{
_value = value;
}
}
5. Attach Attributes to the Backing Fields of Auto-Properties
Sometimes you need to attach an attribute to the compiler-generated backing field of an auto-implemented property (for example, to control serialization). C# 7.3 introduces a new field:
specifier for attributes to make this possible.
public class MyData
{
[field: NonSerialized]
public string MyProperty { get; set; }
}
Conclusion
C# 7.3 is a point release focused on developer quality of life and performance. While it doesn't contain any headline-grabbing features, the small improvements to tuples, generics, and in
parameters all contribute to making the language more pleasant and efficient to work with. These incremental refinements are a key part of the C# language's continued evolution.