阅读本文也许需要 2 分钟。

大家好,这是 C# 9.0 新特征系列的第 4 篇文章。

熟悉函数式编程的童鞋一定对“只读”这个词不生疏。为了保证代码块自身的“贞洁”,函数式编程是不能随便“弄脏”外来事物(参数、变量等)的,以是“只读”对函数式编程非常重要。

为了厚实 C# 对函数式编程支持,较新的 C# 版本引入了一些很有用的新特征。好比 C# 8 中就对 struct 类型的方式增添了 readonly 修饰符支持,被 readonly 修饰的方式是不能修改该方式所在类的属性的。举个例子:

public struct FooValue
{
    private int A { get; set; }
    public readonly int IncreaseA()
    {
        A = A + 1; // 报错
        return A;
    }
}

而 C# 9 又进一步增添了对“只读”的支持,此次增添了 init-only 属性和 record 相关特征,下面逐一先容。

Init-only 属性

我们知道类的属性有 set 和 get 两种接见器,现在 C# 9 增添一种属性接见器:init。init 是 set 接见器的变体,它的作用是使属性只能在工具初始化的时刻对其赋值,之后该属性就是只读的,因此叫 init-only 属性。使用方式如下:

public class Foo
{
    public string PropA { get; init; }
    public string PropB { get; init; }
}

赋值操作:

var foo = new Foo {  PropA = "A", PropB = "B" };
foo.PropA = "AA"; // 报错,PropA 此时是只读的!

由于 init 是在初始化阶段赋值,以是它可以在类内部修改 readonly 修饰的字段。好比:

public class Foo
{
    private readonly string propA;
    private readonly string propB;

    public string PropA
    {
        get => propA;
        init => propA = (value ?? throw new ArgumentNullException(nameof(propA)));
    }
    public string PropA
    {
        get => propB;
        init => propB = (value ?? throw new ArgumentNullException(nameof(propB)));
    }
}

若是你知道在组织函数中可以对只读字段/属性赋值就自然也明白这一点。

纪录 (Record)

做过财政系统的人都知道买卖纪录一旦入账是不能修改的,若是录入错误,就要新录入一笔负的纪录把之前的红冲掉,再录入准确的纪录。应对类似这种只读纪录的场景,C# 9 引入了 Record(纪录,下文均使用中文的“纪录”)的观点,它用来支持整个工具的只读特征(即实例化后为只读)。使用方式如下:

public data class Foo
{
    public string PropA { get; init; }
    public string PropB { get; init; }
}

这里用了一个 data 关键字,示意该类的工具只是纯粹的纪录值,它不是可修改的状态(在函数式编程中,所有的数据修改都是状态在发生变化)。

上面的太麻烦了,可以这样简写:

public data class Foo
{
    string PropA;
    string PropB;
}

默认属性都是 public 的,若是实在要改为 private,可以在属性界说前面加上 private 修饰符。

定位纪录 (Positional Record)

有时刻为了初始化更利便,可以界说组织函数来给属性赋值,初始化时只需要把属性值按顺序传给组织函数即可,这个操作称为定位组织(Positional Construction)。同样,也可以使用解构函数(Deconstructor)来实现属性的解构,即根据解构函数的参数顺序从工具中提取属性的值,被称为定位解构(Positional Deconstructor)。实现了定位组织或定位解构的纪录称为定位纪录(Positional Record)。下面是一个定位纪录的实现:

public data class Foo
{
    string PropA;
    string PropB;
    public Foo(string propA, string propB)
      => (PropA, PropB) = (propA, propB);
    public void Deconstruct(out string propA, out string propB)
      =>  (propA, propB) = (PropA, PropB);
}

这个写法太麻烦了,可以直接简写为:

public data class Foo(string PropA, string PropB);

这样简短一句代码,其内部默认实现了 init-only 自动属性,且同时为所有属性界说了组织函数和解构函数。

使用示例:

var foo = new Foo("AA", "BB");  // 组织定位
var (a, b) = foo;               // 解构定位

可以想象,纪录的大部分使用场景,以上简写的写法能知足需求。若有特殊场景,就不能简朴,需要举行自界说修改其默认行为。

with 表达式

当处置不能变数据时,若要天生差别的状态,一个常见的场景是在一条旧纪录基础上拷贝一条新的纪录。好比我们要修改 Foo 工具的 PropA 属性,我们就要拷贝该工具天生一个新的工具。这个操作在函数式编程中被称为“非破坏性修改 (non-destructive mutation)”。为了支持纪录这个操作,C# 9 引入了 with 表达式,它可以很利便在一条原有纪录基础上建立一条新纪录。示例:

var other = foo with { PropA = "AA" };

with 表达式内部其实是通过一个默认的 protected 组织函数来实现的,大致如下:

protected Foo(Foo original)
{
    // 拷贝 original 的所有字段
}

若是默认实现的字段拷贝不符合你的需求,你也可以手动实现这个组织函数。

今天就分享到这里,敬请期待一下篇关于 C# 9 新特征的文章!

,

欧博电脑版下载

欢迎进入博电脑版下载(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。

发布评论

分享到:

皇冠即时比分:超模吉吉·哈迪德再曝孕肚写真 湿发造型四肢纤细
2 条回复
  1. 欧博亚洲
    欧博亚洲
    (2020-09-01 00:07:08) 1#

    欧博官网手机欢迎进入欧博官网手机(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。还有吗?还想看

    1. allbet欧博真人客户端
      allbet欧博真人客户端
      (2020-09-01 12:35:04)     

      联博接口www.326681.com采用以太坊区块链高度哈希值作为统计数据,联博以太坊统计数据开源、公平、无任何作弊可能性。联博统计免费提供API接口,支持多语言接入。挺好的,要自信

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。