In this tutorial, I'll introduce you to new features in C# 8.0

To play the demo, you need install Visual Studio 2019 Preview, then create a new console application project. Next, Right click on your project and select properties. At the Build tab, click Advanced button, then select C# 8.0 beta version

Nullable reference types

The nullable reference type feature intends to warn you about unsafe behavior in code

using static System.Console;

class Program
{
    static void Main(string[] args)
    {
        string str = null;
        WriteLine($"The first letter of {str} is {str[0]}");
    }
}

Rebuild your project you can't see any warns. But when you run the project you get an error 

System.NullReferenceException: 'Object reference not set to an instance of an object.'

Now, change 'string str = null' to 'string? str = null'

Rebuild your project again. You will get a warn

Warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.

Ranges and indices

using System.Collections.Generic;
using static System.Console;

class Program
{
    static void Main(string[] args)
    {
        foreach (var name in GetLanguages())
        {
            WriteLine(name);
        }
        ReadKey();
    }

    static IEnumerable<string> GetLanguages()
    {
        string[] names =
        {
            "C#", "VB.NET", "C/C++", "Java", "JavaScript"
        };
        foreach (var name in names)
        {
            yield return name;
        }
    }
}

Right click on your project, then select Manage Nuget Packages. Next, Search 'System.Range', then install it

You can change 'foreach (var name in names)' to 'foreach (var name in names[0..4])'

Or you can write

Range range = 0..4; 
foreach (var name in names[range])
    yield return name;

Asynchronous streams

 await foreach (var name in GetLanguageAsync())

Default implementations of interface members

In C# 8.0 let you provide a body for an interface member

interface IStudent
{
    void Add(string id, string fullName, string className);
    void Add(Student obj) => Add(obj.id, obj.FullName, "A1");// New overload
}

class StudentRepository : IStudent
{
    public void Add(string id, string fullName) { ... }
    //Add(Student obj) gets default implementation
}

The StudentRepository class doesn’t have to implement the Add(Student) overload of IStudent, because it's declared with a default implementation.

Now you can add new members to existing public interfaces as long as you provide a default implementation to existing implementers.