C# 7.3 is a minor release with a few enhancements to the existing features.
Features for better performance of safe code
-
- Access to fixed fields without pinning.
- Use of initializers on stackalloc arrays.
- Use of fixed statements with any type that supports a pattern.
- Use of additional generic constraints.
- Reassign of ref local variables.
Some enhancements on the existing features
-
- Test
==
and!=
with tuple types. - Attach attributes to the backing field of auto-implemented properties.
- Method resolution when arguments differ by in has been improved.
- Test
- Overload resolution
Let’s discuss the above in more detail
Overload Resolution
The resolution rules for overload methods have always been in question as it would pick one or more methods, though all but one could not be used, which is annoying.
With 7.3, this rule has been improved and now the compiler is able to make the obvious choice and select a method without giving compiler error. The detailed proposal is outlined below –
- When a method group contains both instance and static members, we discard the instance members if invoked without an instance receiver or context, and discard the static members if invoked with an instance receiver. When there is no receiver, we include only static members in a static context, otherwise both static and instance members. When the receiver is ambiguously an instance or type due to a color-color situation, we include both. A static context, where an implicit this instance receiver cannot be used, includes the body of members where no this is defined, such as static members, as well as places where this cannot be used, such as field initializers and constructor-initializers.
- When a method group contains some generic methods whose type arguments do not satisfy their constraints, these members are removed from the candidate set.
- For a method group conversion, candidate methods whose return type doesn’t match up with the delegate’s return type are removed from the set.
Tuple Comparisons
Allow expressions t1 == t2 where t1 and t2 are tuples or nullable tuple types of same cardinality, and evaluate them roughly as temp1.Item1 == temp2.Item1 && temp1.Item2 == temp2.Item2 (assuming var temp1 = t1; var temp2 = t2;).
So to compare two operands, C# 7.3 uses two points –
- Both should be tuples
- Both should have matching cardinality
Both operands are evaluated in order from left to right. Each pair of elements is then used as operands to bind the operator ==
(or !=
), recursively.
Potential breaking change in tuple comparison –
If someone wrote their own ValueTuple
types with an implementation of the comparison operator, it would have previously been picked up by overload resolution. But since the new tuple case comes before overload resolution, we would handle this case with tuple comparison instead of relying on the user-defined comparison.
Auto-Implemented Property Field-Targeted Attributes
Auto-implemented properties have always been useful, but not in the case of serialization. With the new version of C#, when you are adding an attribute to auto-implemented property, just add the modifier field:
This allow developers to apply attributes directly to the backing fields of auto-implemented properties.
[Serializable] public class Class{ [field: NonSerialized] public string Property1 { get; set; } }
Unmanaged Type constraint
The unmanaged constraint feature will give language enforcement to the class of types known as “unmanaged types”. This new feature uses the “unmanaged” keyword to indicate the generic type must be a “type which is not a reference type and doesn’t contain reference type fields at any level of nesting.”
Unmanaged types include:
- The primitives types such as, sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool
- Any enum type
- Pointer types
- User defined structs
Stack Allocated Arrays
With this feature, the same syntax used to specify the values for elements in an array while initializing can be applied to arrays that are declared with stackalloc:
int* pArr = stackalloc int[3] {1, 2, 3};
int* pArr2 = stackalloc int[] {1, 2, 3};
Span<int> arr = stackalloc [] {1, 2, 3};
The stackalloc
keyword is used in an unsafe code context to allocate a block of memory on the stack.
Wondering what could be the new features in the next major release C# 8.0. Click here to know about the new features.