编程语言
首页 > 编程语言> > C# 8.0的计划特性

C# 8.0的计划特性

作者:互联网

原文:C# 8.0的计划特性

虽然现在C# 7才发布不久,并且新的版本和特性还在增加中,但是C# 8.0已经为大家公开了一些未来可能出现的新特性。

*注:以下特性只是计划,可能在将来的正式版本会有一些差异

 

1.Nullable Reference Types

该特性其实本来计划在C#7.x中就引入,但是却被推迟到了下一个版本中。目的是为了避免引用为null的时候而导致的错误。

其核心思想是允许变量类型定义指定是否可以为它们分配空值:

1 IWeapon? canBeNull;
2 IWeapon cantBeNull;
?
123canBeNull = null;       // no warningcantBeNull = null;      // warningcantBeNull = canBeNull; // warning

此时当申明可为nullable的对象赋值为null的时候,编译器就不会提示警告。

?
12345canBeNull.Repair();       // warningcantBeNull.Repair();      // no warningif (canBeNull != null) {    cantBeNull.Repair();  // no warning}

2.Records

records是一个新的语法糖,它简化了原来创建简单类的过程,通过一条语句就可以创建出一个标准的C# 类。

例如下面的代码:

?
1public class Sword(int Damage, int Durability);

它相对于原来的写法是:

?
1234567891011121314151617181920212223242526272829303132333435public 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。

同时我们还看到在倒数第二个方法是一个解构的方法,它允许我们将Record所创建的对象进行解构为一个元组(关于解构的特性,可以参加C#7.0的特性)

?
1var (damage, durability) = sword;

最后的一个With方法可以供我们创建一个不同属性值的Sword副本对象。

?
1var (damage, durability) = sword;

当然,对于With的方法,C# 也提供了一个语法糖写法:

?
1var strongerSword = sword with { Damage = 8 };

3.Default Interface Methods

在以往的C# 语法中,我们都知道一个Interface只能够申明方法体,却不能对其进行实现:

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

按照以往的写法,我们一般是尝试写一些抽象类来作为替代实现:

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

但在C# 8.0中可能引入接口的方法实现功能。

4.Asynchronous Streams

C# 目前是已经支持了迭代器( iterators ) 和 异步方法。在C#8.0中打算结合现有的两者,推出异步的迭代器,它将基于异步的 IEnumerable 和 IEnumerator 接口:

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

此外,使用异步迭代器还需要IDisposable接口的异步版本:

?
1234public interface IAsyncDisposable{    Task DisposeAsync();}

接下来,在使用的时候,可能看上去就像下面这样:

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

当然,这个写法对我们C#的开发人员来说可能还不是太眼熟,因为在传统的迭代器写法上,我们已经习惯了Foreach的写法,因此对于异步迭代器来说,它也会存在对应的一个foreach版本,就如同下面这样:

?
1234foreach await (var item in enumerable){    Use(item);}
?
1234567891011121314async IAsyncEnumerable<int> AsyncIterator(){    try    {        for (int i = 0; i < 100; i++)        {            yield await GetValueAsync(i);        }    }    finally    {        await HandleErrorAsync();    }}

5.Ranges

这个特性可能相对来说就比较有趣了,它允许我们使用简短的语法来定义一个区间值,比如:

?
1var range = 1..5;

这样就产生了一个表示已声明范围的结构:

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

在实际的应用过程中,我们可以这样来使用它:

?
1234567Span<T> this[Range range]{    get    {        return ((Span<T>)this).Slice(start: range.Start, length: range.End - range.Start);    }}
?
1234foreach (var index in min..max){    // process values}
?
123456switch (value){    case 1..5:        // value in range        break;}

这个特性看上去果然非常的good。

6.Generic Attributes

对泛型特性的支持将为需要类型作为参数的属性提供更好的语法。目前,只能使用以下语法将类型传递给特性:

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

当有了泛型特性之后,我们可以尝试这样做:

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

  

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

7.Default Literal in Deconstruction

在C# 7.x中引入了default 默认值和解构的概念。在C# 8中将实现两者的共同作用。

要为C#7中的元组的所有成员分配默认值,必须使用元组赋值语法:

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

通过支持解构语法中的默认文字,以下语法也可以实现相同的功能:

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

8.Caller Argument Expression

在C#5中,引入了CallerMemberName, CallerFilePath and CallerLineNumber特性,方便我们能够获取到有关调用方法的一些信息。

就像CallerMemberName在INotifyPropertyChanged中的应用,对于WPF开发的童鞋就在熟悉不过了:

?
123456789101112131415161718192021222324class 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的特性,它捕获调用方法中的参数:

?
1234567891011public 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));    }}

9.Target-typed new Expression

这可能也将成为将来常用的一个新特性,它将更加简化在申明时候的类型推断。

比如以往我们申明一个对象是这个样子的:

?
12Dictionary<string, string> dictionary = new Dictionary<string, string>(); // without var keywordvar dictionary = new Dictionary<string, string>(); // with var keyword

但是在C#8中,将简化成这样:

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

 

Over:

当然距离C#8真是发布可能还要等一段时间,期间可能也会增加一些其他的特性,真正的体验效果还是一起期待8.0的发布吧

 

标签:8.0,Durability,C#,Damage,特性,int,public
来源: https://www.cnblogs.com/lonelyxmas/p/12065786.html