The coming of C#8

Nullable reference types

Once, value types couldn’t be null, but that changed with the introduction of  System.Nullable<T> in C# 2, althoughthe syntactic sugar of the ‘?’ modifier which renders byte? and System.Nullable<byte> interchangeable is what stuck the most. 

Of course for reference types null was always legal, but that’s about to change by extending the T? syntax to reference types too in order to allow :“developers to express whether a variable, parameter or result of a reference type is intended to be null or not and provide warnings when such variables, parameters, and results are not used according to that intent”. 

This makes the following possible: 

class Person
{
//everyone has a first and a last name, but only some //people have a middle name.
public string FirstName;   // Not null 
public string? MiddleName; // May be null    public string LastName;    // Not null
}

 It is assumed that the intent of an unadorned reference type T is for it to be non-null. 

Default Interface Methods

 Similarly to Java’s “Default Methods” is the introduction of the “Default Interface Methods”, that is methods in interfaces with concrete implementations.

As always the problem with interfaces is that extending them requires all classes implementing them to also change to accommodate the change. 

Under this proposal, class C which implements the interface IA is not forced to also implement IA’s concrete method: 

interface IA
{
  void M() { WriteLine("IA.M"); }
}
class C : IA { } \\

This feature means that future and extended versions of the interface don’t have to break existing code. 

Fixed Sized Buffers

This is mostly a performance-enhancing issue but especially important for those in need of breaking away of the CLR’s managed boundaries, like when interoperating with C DLL’s. 

In such scenarios, you are very likely to stumble upon cases such as: 

internal unsafe struct MyBuffer
{
    public fixed uint Reserved[28]; //array of 28 uints
}

where with ‘fixed’ you pin the necessary memory for the unmanaged dll to consume.However this operation has to be wrapped in an ‘unsafe’ context and with it, all the associated dangers. 

The proposal wants managed code to be able to work with fixed-size arrays while still getting the benefits of safe code, such as bounds checking.’unsafe’ has to go. It should go down that you can also interop with unmanaged code in a safe way by using MarshalAs.

For example, the previous ‘fixed’ example can be written as: 

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)]public uint[] Reserved;

a snippet taken from  the P/Invoke code I extensively use in the UER app which interoperates with the WinRAR’s unrar.dll written in C++.  It needs a struct defined as: 

[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)]public struct OpenArchiveDataEx_template{public string ArcName;[MarshalAs(UnmanagedType.LPWStr)]public string ArcNameW;public uint OpenMode;public uint OpenResult;public string CmtBuf;public uint CmtBufSize;public uint CmtSize;public uint CmtState;public uint Flags;public IntPtr Callback;public int UserData;[MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)]public uint[] Reserved;...[DllImport("unrar.dll",SetLastError=true)]public static extern IntPtr RAROpenArchiveEx(ref OpenArchiveDataEx_template OpenArchiveDataEx_instance); 

Here the compiler takes care of the managed to unmanaged communication but at the cost of performance due to the allocation of the structures and marshaling of the data.’Fixed’  then, allows direct communication by passing pointers to the unmanaged struct, something that gets translated to much greater enhanced performance.

The proposal builds on this by allowing fixed buffers to also be used in safe environments. Among the rest of the proposals, ones that stand out include Recursive Pattern Matching, Static Delegates, Covariant Returns and Asynchronous streams.

{//everyone has a first and a last name, but only some //people have a middle name.public string FirstName;   // Not null    public string? MiddleName; // May be null    public string LastName;    // Not null}

 It is assumed that the intent of an unadorned reference type T is for it to be non-null. Default Interface Methods Similarly to Java’s “Default Methods” is the introduction of the “Default Interface Methods”, that is methods in interfaces with concrete implementations.

As always the problem with interfaces is that extending them requires all classes implementing them to also change to accommodate the change. Under this proposal, class C which implements the interface IA is not forced to also implement IA’s concrete method:

interface IA{    void M() { WriteLine("IA.M"); }}class C : IA { } 

This feature means that future and extended versions of the interface don’t have to break existing code. 

Fixed Sized Buffers

This is mostly a performance-enhancing issue but especially important for those in need of breaking away of the CLR’s managed boundaries, like when interoperating with C DLL’s. In such scenarios, you are very likely to stumble upon cases such as: 

internal unsafe struct MyBuffer{    public fixed uint Reserved[28]; //array of 28 uints}

where with ‘fixed’ you pin the necessary memory for the unmanaged dll to consume.However this operation has to be wrapped in an ‘unsafe’ context and with it, all the associated dangers. 

The proposal wants managed code to be able to work with fixed-size arrays while still getting the benefits of safe code, such as bounds checking.’unsafe’ has to go. It should go down that you can also interop with unmanaged code in a safe way by using MarshalAs. For example, the previous ‘fixed’ example can be written as: 

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)]public uint[] Reserved; 

a snippet taken from  the P/Invoke code I extensively use in the UER app which interoperates with the WinRAR’s unrar.dll written in C++.  It needs a struct defined as: 

[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)]public struct OpenArchiveDataEx_template{public string ArcName;[MarshalAs(UnmanagedType.LPWStr)]public string ArcNameW;public uint OpenMode;public uint OpenResult;public string CmtBuf;public uint CmtBufSize;public uint CmtSize;public uint CmtState;public uint Flags;public IntPtr Callback;public int UserData;[MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)]public uint[] Reserved;...00[DllImport("unrar.dll",SetLastError=true)]public static extern IntPtr RAROpenArchiveEx(ref OpenArchiveDataEx_template OpenArchiveDataEx_instance); 

Here the compiler takes care of the managed to unmanaged communication but at the cost of performance due to the allocation of the structures and marshaling of the data.

‘Fixed’  then, allows direct communication by passing pointers to the unmanaged struct, something that gets translated to much greater enhanced performance.

The proposal builds on this by allowing fixed buffers to also be used in safe environments. Among the rest of the proposals, ones that stand out include Recursive Pattern Matching, Static Delegates, Covariant Returns and Asynchronous streams.

Credit: iProgrammer