在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
相关产品推荐
相关产品推荐

