You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C#11中使用required关键字时,能否为setter设置不同访问修饰符?

问题:使用C#11 required关键字实现必填且仅类内部/子类可修改的属性

我想要实现以下效果:实例化Person类时必须提供FirstName属性值,该属性可被任意访问,但仅能在Person类及其子类中修改。我知道可以通过构造函数实现,但想使用C#11的required关键字或类似新语法来实现。

我尝试编写如下代码:

public class Person
{
    public required string FirstName { get; protected set; }

    public void ChangeNameToMike()
    {
        FirstName = "Mike";
    }
}

但出现错误:

CS9032 Required member 'Person.FirstName' cannot be less visible or have a setter less visible than the containing type 'Person'

使用构造函数的方式可以正常运行,但我希望不借助构造函数实现相同效果:

public class Person
{
    public string FirstName { get; protected set; }

    public Person(string firstName)
    {
        FirstName = firstName;
    }

    public void ChangeNameToMike()
    {
        FirstName = "Mike";
    }
}

原因分析

报错的核心原因是:C#11对required成员有强制要求——成员的可访问性(包括属性的setter)不能低于包含它的类型。当用对象初始化器创建实例时,外部代码需要能够设置required成员,但protected setter对外部代码不可见,两者冲突导致编译错误。

解决方案

要实现需求,不能直接将required与protected setter结合,可通过以下两种方式替代:

方案1:私有字段 + Required Init属性 + Protected修改方法

public class Person
{
    private string _firstName;

    // Required属性保证初始化时必须赋值,外部仅能读取
    public required string FirstName
    {
        get => _firstName;
        init => _firstName = value;
    }

    // 提供protected方法供子类和自身修改值
    protected void UpdateFirstName(string newName)
    {
        _firstName = newName;
    }

    public void ChangeNameToMike()
    {
        _firstName = "Mike"; // 类内部可直接修改私有字段
    }
}

// 子类示例
public class Employee : Person
{
    public void ChangeNameToJohn()
    {
        UpdateFirstName("John"); // 通过protected方法修改
    }
}

方案2:Protected字段 + Required Init属性

public class Person
{
    // Protected字段允许自身和子类直接修改
    protected string _firstName;

    // Required属性保证初始化必填,外部仅能读取
    public required string FirstName
    {
        get => _firstName;
        init => _firstName = value;
    }

    public void ChangeNameToMike()
    {
        _firstName = "Mike";
    }
}

// 子类示例
public class Employee : Person
{
    public void ChangeNameToJane()
    {
        _firstName = "Jane"; // 子类可直接修改protected字段
    }
}

两种方案都无需构造函数,同时满足:

  • 实例化时必须提供FirstName
  • 外部仅能读取FirstName
  • 仅Person类及其子类可修改FirstName的值

内容的提问来源于stack exchange,提问作者Kevin Németh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 20:25:17