Scheduled New C # 8.0 Features


All the tools previously presented in minor C # versions are designed not to change the language too much. They are rather syntactic improvements and small additions to the new features of C # 7.0 .


This approach was deliberate, and it remains valid.


More serious changes that require more work at all stages of development (design, implementation and testing) will continue to be released only with major releases of the language. And although the final minor version of C # 7 has not yet been released, the team is already actively working on the following main version of the language: C # 8.0.


In this article, I plan to present a selection of currently planned functions that are likely to be in the final release. All of them are in the early stages of development and are subject to change.


Nullable Reference Types


This tool has already been proposed in the early stages of developing C # 7.0, but was postponed until the next major release. Its purpose is to help the developer avoid unhandled NullReferenceException exceptions.


The main idea is to allow when determining the type of a variable to indicate whether it can be null or not:


IWeapon? canBeNull;
IWeapon cantBeNull;

null , null -null , ( , , ):


canBeNull = null;       //  
cantBeNull = null;      // 
cantBeNull = canBeNull; // 

, nullable- null:


canBeNull.Repair();       // 
cantBeNull.Repair();      //  
if (canBeNull != null) {
    cantBeNull.Repair();  //  
}

, – , - ?


, : , null. , null- .


nullability , . , .


Visual Studio 2017 15.6 update.


Records


, - C# , -.


:


public class Sword(int Damage, int Durability);

:


public class Sword : IEquatable<Sword>
{
    public int Damage { get; }
    public int Durability { get; }

    public Sword(int Damage, int Durability)
    {
        this.Damage = Damage;
        this.Durability = Durability;
    }

    public bool Equals(Sword other)
    {
        return Equals(Damage, other.Damage) 
            && Equals(Durability, other.Durability);
    }

    public override bool Equals(object other)
    {
        return (other as Sword)?.Equals(this) == true;
    }

    public override int GetHashCode()
    {
        return (Damage.GetHashCode() * 17 + Durability.GetHashCode());
    }

    public void Deconstruct(out int Damage, out int Durability)
    {
        Damage = this.Damage;
        Durability = this.Durability;
    }

    public Sword With(int Damage = this.Damage, int Durability 
        = this.Durability) => new Sword(Damage, Durability);
}

, , . GetHashCode - Dictionary Hashtable. Deconstruct :


var (damage, durability) = sword;

, , , . , , . , , With, :


var strongerSword = sword.With(Damage: 8);

, :


var strongerSword = sword with { Damage = 8 };

Recursive Patterns


C# 7.0. 8.0 :


. Deconstruct():


if (sword is Sword(10, var durability)) {
    //  ,  Damage = 10
    // durability   sword.Durability
}

(tuple) :


switch (state, transition)
{
    case (State.Running, Transition.Suspend):
        state = State.Suspended;
        break;
}

switch , . , :


state = (state, transition) switch {
    (State.Running, Transition.Suspend) => State.Suspended,
    (State.Suspended, Transition.Resume) => State.Running,
    (State.Suspended, Transition.Terminate) => State.NotRunning,
    (State.NotRunning, Transition.Activate) => State.Running,
    _ => throw new InvalidOperationException()
};

Default Interface Methods


, C# , :


interface ISample
{
    void M1();                                    // 
    void M2() => Console.WriteLine("ISample.M2"); // 
}

, :


abstract class SampleBase
{
    public abstract void M1();
    public void M2() => Console.WriteLine("SampleBase.M2");
}

, C# 8 , . , .


. , . , . , . , .


C#, .


, . , – trait .


, , . C# 8.0 , :



Asynchronous Streams


C# . C# 8.0, . IEnumerable IEnumerator:


public interface IAsyncEnumerable<out T>
{
    IAsyncEnumerator<T> GetAsyncEnumerator();
}

public interface IAsyncEnumerator<out T> : IAsyncDisposable
{
    Task<bool> MoveNextAsync();
    T Current { get; }
}

, IDisposable:


public interface IAsyncDisposable
{
    Task DisposeAsync();
}

:


var enumerator = enumerable.GetAsyncEnumerator();
try
{
    while (await enumerator.WaitForNextAsync())
    {
        while (true)
        {
            Use(enumerator.Current);
        }
    }
}
finally
{
    await enumerator.DisposeAsync();
}

– , while(true). - , . , , . , , .


, . , foreach. :


foreach await (var item in enumerable)
{
    Use(item);
}

, foreach , .


, yield. , :


async IAsyncEnumerable<int> AsyncIterator()
{
    try
    {
        for (int i = 0; i < 100; i++)
        {
            yield await GetValueAsync(i);
        }
    }
    finally
    {
        await HandleErrorAsync();
    }
}

LINQ.


Ranges


:


var range = 1..5;

, :


struct Range : IEnumerable<int>
{
    public Range(int start, int end);
    public int Start { get; }
    public int End { get; }
    public StructRangeEnumerator GetEnumerator();
    // overloads for Equals, GetHashCode...
}

:



Span<T> this[Range range]
{
    get
    {
        return ((Span<T>)this).Slice(start: range.Start, 
            length: range.End - range.Start);
    }
}


foreach (var index in min..max)
{
    //  
}


switch (value)
{
    case 1..5:
        //   
        break;
}

step – , . – ( ). Python, .


, , .., . , .


, , , ..:


a[start:end] #   start  end-1
a[:end]      # items    end-1

, .


Generic Attributes


. , , :


public class TypedAttribute : Attribute
{
    public TypedAttribute(Type type)
    {
        // ...
    }
}

, :


public class TypedAttribute<T> : Attribute
{
    public TypedAttribute()
    {
        // ...
    }
}

, , :


public TypedAttribute(T value)
{
    // ...
}

Default Literal in Deconstruction


C# 7, :


(int x, int y) = (default, default);

default, :


(int x, int y) = default;

Caller Argument Expression


C# 5, CallerMemberName, CallerFilePath CallerLineNumber) .


CallerMemberName INotifyPropertyChanged:



class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private int property;

    public int Property
    {
        get { return property; }
        set
        {
            if (value != property)
            {
                property = value;
                OnPropertyChanged();
            }
        }
    }
}

C# 8 CallerArgumentExpression, , :


public Validate(int[] array, [CallerArgumentExpression("array")] string arrayExpression = null)
{
    if (array == null)
    {
        throw new ArgumentNullException(nameof(array), $"{arrayExpression} was null.");
    }
    if (array.Length == 0)
    {
        throw new ArgumentException($"{arrayExpression} was empty.", nameof(array));
    }
}

, , .


Target-typed new Expression


, var ( ) :


Dictionary<string, string> dictionary = new Dictionary<string, string>(); //  var
var dictionary = new Dictionary<string, string>(); //  var

(), , :


class DictionaryWrapper
{
    private Dictionary<string, string> dictionary = new Dictionary<string, string>();
    // ...
}

C# 8, new, :


class DictionaryWrapper
{
    private Dictionary<string, string> dictionary = new();
    // ...
}

, , . , .


Type/typedef, , ! , / .


Ordering of ref and partial Modifiers on Type Declarations


C# , partial struct class.


ref C# 7.2, partial , , ref struct, partial partial, .


, :


public ref struct NonPartialStruct { }
public ref partial struct PartialStruct { }

C# 8, , :


public partial ref struct PartialStruct { }


C# 8 . .
, C# 8.0, . , , . , , .


, , . .


C# 7.1, 7.2 and 7.3 — New Features (Updated).


, C#. C# — - ? , :


  1. var . . . , .
  2. Go . . -. , , ( ) .
  3. C# . ( .Net Framework 1.1), ( «» LINQ – , SQL, ). , .
  4. - typedef, , , (var ). new(), ( ).

, , . GO C# . , . C# , – .


? . . C# – Common Language Infrastructure (CLI). CLI , , . Java/Kotlin. , ?


( Nullable Reference Types). , .

Source: https://habr.com/ru/post/413065/


All Articles