The changes may be small, but we still need to keep up-to-date. How does moving to version 10 change C#? A look at three features that make it really worthwhile.
There isn't much that can be changed in C# without worrying about backward compatibility, but there are some nice additions in C# 10.
Lambdas
Page 185
It has been a minor annoyance that you have to specify a type for a lambda when the type is fairly obvious from its parameters. Now the compiler will infer one of the standard generic function types and apply it for you. For example, you used to have to write:
HelloType HelloInst = (param1) =>
{
MessageBox.Show("Hello delegate World" + param1.ToString());
return ++param1;
};
where HelloType was defined as a delegate somewhere else in the program. Now you can write:
var HelloInst = (int param1) =>
{
MessageBox.Show("Hello delegate World" + param1.ToString());
return ++param1;
};
and the compiler will work out that HelloInst is an instance of Func<int,int>. If you hover over HelloInst then the compiler will tell you its type.
This sort of thing also works with method groups. Where you had to write
HelloType Hello= MyObject.myfunction;:
you can now write:
var Hello= MyObject.myfunction;:
as long as HelloInst isn't overloaded. Again the compiler will guess that Hello is Func<int,int>.
Not being able to declare a return type for a lambda was sometimes an irritation when different types could be returned and now you can specify the return type as you would for a method:
var HelloInst = int (int param1) =>
{
MessageBox.Show("Hello delegate World" + param1.ToString());
return ++param1;
};
Notice the int in front of the parameters.
Finally you have long been able to apply attributes to methods but not lambdas now you can. If you set an attribute target to Method you can annotate a lambda.
[myattribute]var HelloInst = int (int param1) =>
{MessageBox.Show("Hello delegate World" +
param1.ToString());
return ++param1;
}
The only problem is that the attribute will not be called when the lambda is - so it doesn't really work as an attribute.
Structs
Page 57
The biggest change to structs is permission to create a parameterless constructor. All structs have a default parameterless constructor that sets all of the fields to default values appropriate for their type. This prohibited you from defining your own parameterless constructor, but now you can. If you don't the fields are set to defaults, but if you do you can see the fields to defaults of your own choice. For example, if you define:
public struct Point
{
public int x, y;
}
then when you create a Point:
Point p;
the fields are set to zero. However, if you add a constructor:
public struct Point
{
public int x, y;
public Point()
{
x = 100;
y = 100;
}
}
You can create a struct with x and y set to 100 using:
Point p=new Point();
Page 63
Another case of structs being second class citizens has been fixed as now they can be records too: In many ways records are an alternative to structs with reference semantics, but now you can have the convenience of records, but with value semantics. For example, instead of:
public record Staff { public string name { get; init; } public int age { get; set; } }
which creates a record class you can use:
public record struct Staff { public string name { get; init; } public int age { get; set; } }
which creates a record struct.
One of the nice things about records is the with expression that allows you to create partially initialized records. You can now use this will all structs including record structs: For example:
Staff you = me with { name = "harry" };
This creates a copy of the me record but with the name changed to harry. The with expression creates a completely new copy of the struct or record then uses the object initializer to change any fields mentioned and then sets the variable to refer to the new object.
Pattern Matching
Page 33
There are some other small improvements but the ability to shorten nested property patterns will be useful to anyone over using pattern matching. Instead of
is {Address:{City: "London"}}
you can write the more natural:
is (Address.City: "London"}
There is also a major preview included that you can enable as an option. If it makes it into C# 11 it might make generics much more powerful by allowing operators on generic types, among other things.