This is the fifth day of my participation in Gwen Challenge
“This article has participated in the weekend learning plan, click to see details”
This is the fifth day of my participation in the Gwen Challenge.
This article has participated in the weekend study program, click to see more details
preface
I didn’t want to write this article because I was lazy, but so many people showed interest that I decided to write it anyway.
The last few preview releases of.NET 6 have been working on experiences (Hot Reload, Linker, etc.), platform support (Android, iOS, etc.), toolchains (CrossGen2, PGO tools, AOT for WASM, etc.), JIT (e.g LSRA, Jump threading, PGO, and Guarded devirtualization, as well as keeping structs in registers and so on), GC (Regions, etc.), and BCL (TimeOnly, DateOnly, and Json DOM, etc.), but nothing in C# 10 has been announced, not even at Build 2021. While the implementation of many features is nearing completion, let’s take a look at what C# 10 can bring.
Of course, not all of the features listed below will necessarily make it into C# 10 and may differ from this article, but I’ve added a percentage after each feature to indicate the likelihood of eventual implementation, just for your information.
Backing Fields (60%)
Many people think “if only I didn’t have to write the field definition by hand” when writing a property because the automatic property didn’t meet their needs. Now this dream has come true:
Copyprivate int myInt;
public int MyInt { get => myInt; set => myInt = value; }
Copy the code
C# 10 added a new field that automatically creates field definitions for properties when used, eliminating the need to manually define fields, hence also called semi-automatic properties.
Copypublic int MyInt { get => field; set => field = value; }
Copy the code
Record Structs (100%)
Records used to only support classes, but now also supports structs, so you can define a record of value type to avoid unnecessary heap allocation:
Copyrecord struct Point(int X, int Y);
Copy the code
with
On Anonymous Objects (80%)
Previously, with could only be used with records, but now it can be extended to anonymous objects. You can use with to create copies of anonymous objects and change their values:
Copyvar foo = new { A = 1, B = "test", C = 4.4 };
var bar = foo with { A = 3 };
Console.WriteLine((bar.A, bar.B, bar.C)); / / (4.4) 3, the test,
Copy the code
Global Usings (80%)
Previously, the using statement was a single file. If you want to use a few namespaces, or define a series of type aliases to be used throughout the project, you need to do this:
Copyusing System.Linq;
using static System.Math;
using i32 = System.Int32;
using i64 = System.Int64;
Copy the code
Then repeat in each file. But now you don’t need to, you can define global using:
Copyglobal using System.Linq;
global using static System.Math;
global using i32 = System.Int32;
global using i64 = System.Int64;
Copy the code
Then you can use it throughout the project.
File Scoped Namespace (90%)
Starting with C# 10 you will be able to specify the namespace of the file at the top of the file instead of having to write a namespace and then wrap the rest of the code inside curly braces. After all, most of the time when we write code we really only write one namespace in a file. It’s also nice to have one less layer of nesting:
Copynamespace MyProject;
class MyClass
{
// ...
}
Copy the code
If written this way, only one namespace can be declared per file.
Constant Interpolated String (100%)
As the name implies, constant string interpolation:
Copyconst string a = "foo";
const string b = $"{a}_bar"; // foo_bar
Copy the code
Constant string interpolation is done at compile time.
Lambda Improvements (100%)
C# 10 significantly improved lambda, expanded usage scenarios, and improved a number of derivations, introducing natural delegate types, and moving functions up to first-class.
Support the Attributes
Copyf = [Foo] (x) => x; // Set lambda
f = [return: Foo] (x) => x; // Set the lambda return value
f = ([Foo] x) => x; // Set lambda parameters
Copy the code
Supports display of specified return value types
Previously C#’s lambda return type was derived, C# 10 now allows the specified lambda type to be displayed at the top of argument lists:
Copyf = int() = >4;
Copy the code
supportref
Such modification
Copyf = ref int (ref int x)= >ref x; // Returns a reference to a parameter
Copy the code
First-class Functions
Methods can be implicitly converted to a Delegate, raising functions to first-class.
CopyDelegate f = 1.GetHashCode; // Func<int>
object g = 2.ToString; // object(Func<string>)
var s = (int x) => x; // Func<int, int>
Copy the code
Pass a function as a variable and then pass an argument to another function:
Copyvoid Foo(Func<int> f)
{
Console.WriteLine(f());
}
int Bar()
{
return 5;
}
var baz = Bar;
Foo(baz);
Copy the code
Natural Delegate Types
Lambda now automatically creates a natural delegate type.
We can use var to create a delegate:
Copyvar f = () => 1; // Func<int>
var g = string (int x, string y) => $"{y}{x}"; // Func<int, string, string>
var g = "test".GetHashCode; // Func<int>
Copy the code
Call lambdas
Thanks to the above improvements, the well-defined lambda created can now be called directly.
Copyvar zero = ((int x) => x)(0); / / 0
Copy the code
Caller Expression Attribute (80%)
Now, the Attribute CallerArgumentExpression is finally useful. With this attribute, the compiler automatically populates the expression string for the call parameter, for example:
Copyvoid Foo(int value, [CallerArgumentExpression("value")] string? expression = null)
{
Console.WriteLine(expression + "=" + value);
}
Copy the code
When you call it like this:
CopyFoo(4 + 5);
Copy the code
It says 4 plus 5 is equal to 9. This is extremely useful for testing, because you can now print the original expression for assert:
Copystatic void Assert(bool value, [CallerArgumentExpression("value")] string? expr = null)
{
if (!value) throw new AssertFailureException(expr);
}
Copy the code
Default supports deconstruction (100%)
Default now supports deconstruction, so tuples can be assigned directly.
Copy(int a, int b, int c) = default; / / (0, 0, 0)
Copy the code
List Patterns (100%)
List Patterns, the last piece of Pattern Matching.
Copyvoid Foo(List<int> list)
{
switch (list)
{
case [4]:
Console.WriteLine("Length 4");
break;
case { 1.2.3 }:
Console.WriteLine("The elements are one, two, three.");
break;
case { 1.2.var x, 5 }:
Console.WriteLine($" the first two elements are 1, 2, the last element is 5, and the penultimate element is{x}");
break;
default:
Console.WriteLine("Other"); }}Copy the code
Again, this pattern is recursive, so you can nest other patterns.
In addition to the use of switch statements above, it can also be used in places such as if and switch Expressions, for example:
Copyvoid Foo(List<int> list)
{
var result = list switch{[4] = >... , {1.2.3} = >... , {1.2.var x, 5} = >... , _ = >... }; }Copy the code
Abstract Static Member in Interfaces (100%)
In C# 10, interfaces can declare abstract static members, and.net’s type system officially has virtual static dispatch capabilities.
For example, you want to define an interface IMonoid that can be added and has zero:
Copyinterface IMonoid<T> where T : IMonoid<T>
{
abstract static T Zero { get; }
abstract static T operator+(T l, T r);
}
Copy the code
It can then be implemented, such as MyInt here:
Copypublic class MyInt : IMonoid<MyInt>
{
public MyInt(int val) { Value = val; }
public static MyInt Zero { get; } = new MyInt(0);
public static MyInt operator+(MyInt l, MyInt r) => new MyInt(l.Value + r.Value);
public int Value { get; }}Copy the code
Then you can write a method to sum IMoniod
.
Copypublic static class IMonoidExtensions
{
public static T Sum<T> (this IEnumerable<T> t) where T : IMonoid<T>
{
var result = T.Zero;
foreach (var i in t) result += i;
returnresult; }}Copy the code
Last call:
CopyList<MyInt> list = new() { new(1), new(2), new(3)}; Console.WriteLine(list.Sum().Value);/ / 6
Copy the code
This feature will also improve the.NET BCL with new interfaces such as IAddable
and INumeric
, implemented for existing types where applicable.
conclusion
That’s about the majority of the new features in C# 10. It’s not guaranteed to look exactly like this article, but it gives you a sense of direction.
There is a good omen in the interface improvements:.NET is finally moving to a type system. CTS, which has barely changed since 2008, is clearly failing to adapt to the language’s evolving needs, and the.net team has clearly signalled that improvements to the type system should be centralized around C# 11, and that this is just the beginning. We’ll see traits, Union types, bottom types and HKT in action soon, too.