C#如何仅通过Action<Class>方法修改类属性 禁止外部直接调用setter
问题原因
readonly修饰符作用在引用类型字段上时,仅限制字段本身不能被重新赋值为新的对象实例,也就是只会阻止UI.Colors = new Colors()这类写法,不会限制你通过字段拿到已有实例的引用后,调用实例上的公开setter修改属性值,这就是UI.Colors.Primary = ConsoleColor.Green依然能执行的原因。
你之前给属性set加private修饰符失效的原因也很简单:private的访问范围仅限Colors类自身内部,你的ConfigureColors方法定义在独立的UI类中,没有权限访问这些私有setter,自然两种修改方式都会报错。
实现方式
用接口隔离读写权限是最清晰的实现思路,不需要修改原有调用逻辑,就能实现读写权限控制:
- 定义一个只包含属性getter的只读接口,作为对外暴露的类型
- 原有Colors类作为内部实现类继承该接口,保留属性的set访问器,设置为仅程序集内部可访问
- UI类对外只暴露只读接口类型的实例,内部持有可写的Colors实例,仅在
ConfigureColors方法中传入可写实例供修改
对应代码如下:
// 对外公开的只读契约,仅包含属性读权限 public interface IReadOnlyColors { ConsoleColor Primary { get; } ConsoleColor Default { get; } ConsoleColor Input { get; } ConsoleColor Success { get; } ConsoleColor Error { get; } ConsoleColor Highlight { get; } } // 内部可写的实现类,不对外部公开 internal class Colors : IReadOnlyColors { public ConsoleColor Primary { get; set; } = ConsoleColor.White; public ConsoleColor Default { get; set; } = ConsoleColor.Gray; public ConsoleColor Input { get; set; } = ConsoleColor.Gray; public ConsoleColor Success { get; set; } = ConsoleColor.Green; public ConsoleColor Error { get; set; } = ConsoleColor.Red; public ConsoleColor Highlight { get; set; } = ConsoleColor.Blue; } public static class UI { // 对外暴露只读接口,外部仅能读取属性值 public static IReadOnlyColors Colors => _colors; // 内部持有可写的实际实例 private static readonly Colors _colors = new(); public static void ConfigureColors(Action<Colors> modification) { modification.Invoke(_colors); } }
最终效果
- 读取属性完全不受影响:
var primaryColor = UI.Colors.Primary;可正常执行 - 通过官方配置方法修改正常可用:
UI.ConfigureColors(colors => { colors.Primary = ConsoleColor.Yellow; // 正常执行 }); - 外部直接赋值会被编译器拦截:
UI.Colors.Primary = ConsoleColor.Green; // 编译报错,IReadOnlyColors未定义set访问器
如果不想额外定义接口,也可以将Colors类嵌套在UI类内部,把属性setter设为UI类可访问的范围,但接口方案的隔离性更好,也不会破坏原有代码的调用习惯,是这类场景的标准实现。
内容的提问来源于stack exchange,提问作者David Shnayder
相关产品推荐
相关产品推荐

