zoukankan      html  css  js  c++  java
  • C# 8.0的计划特性

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

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

    1.Nullable Reference Types

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

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

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

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

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

    2.Records

    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。

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

    var (damage, durability) = sword;

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

    var (damage, durability) = sword;

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

    var strongerSword = sword with { Damage = 8 };

    3.Default Interface Methods

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

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

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

    abstract 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 接口:

    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();
    }

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

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

    5.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)
    {
        // process values
    }
    
    switch (value)
    {
        case 1..5:
            // value in range
            break;
    }

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

    6.Generic Attributes

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

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

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

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

      

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

    7.Default Literal in Deconstruction

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

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

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

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

    (int x, int y) = default;

    8.Caller Argument Expression

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

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

    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));
        }
    }
    

    9.Target-typed new Expression

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

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

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

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

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

    Over:

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

  • 相关阅读:
    excel提取一类具有相似结构的部分数据,2种方式;数据——分列——分割符号/固定宽度;
    excel文字随单元格大小变化
    python操作excel
    Docker容器使用
    阿里云服务器部署好后,浏览器远程访问,提示无法访问此网站;
    StringBuffer和StringBuilder的区别
    【Linux运维-集群技术进阶】集群/分布式环境下5种session处理策略
    mysql如何进行以,分割的字符串的拆分
    Dubbox的介绍和简单示例
    JAVA回调机制(CallBack)详解
  • 原文地址:https://www.cnblogs.com/uoyo/p/9119062.html
Copyright © 2011-2022 走看看