如何通过扩展方法暴露record属性并将原属性设为私有?
解决方案
要实现只能通过扩展方法访问record属性,禁止直接通过名称访问,可以通过以下两种方式实现:
方法一:使用接口隐藏record具体类型
这种方式最彻底,外部代码完全无法接触到record的内部属性,只能通过扩展方法操作:
// 公开的空接口,作为对外暴露的类型 public interface IAxe { } // 文件级私有record,仅当前文件内的代码可访问其成员 file sealed record AxeEnum(string Name, int LevelReq, int ItemId) : IAxe; static class Axe { static readonly Dictionary<int, AxeEnum> _axes = new(); static readonly AxeEnum _steel = new("Steel", 41, 1378); static Axe() { _axes.Add(GetId(_steel), _steel); } // 对外返回接口类型,隐藏具体record实现 public static IAxe GetById(int id) { _axes.TryGetValue(id, out var axe); return axe; } // 扩展方法针对接口实现,内部转换为私有record访问属性 public static int GetLvlReq(this IAxe axe) => ((AxeEnum)axe).LevelReq; public static int GetId(this IAxe axe) => ((AxeEnum)axe).ItemId; public static string GetName(this IAxe axe) => ((AxeEnum)axe).Name; }
优势:
- 外部代码仅能看到
IAxe接口,完全无法访问AxeEnum的任何属性 - 彻底杜绝了直接访问属性的可能
- 符合封装原则,内部实现可自由修改,不影响外部调用
方法二:手动封装record私有字段+内部访问器
如果需要对外暴露AxeEnum类型,但禁止访问其属性,可以手动定义私有字段并提供内部访问方法:
public sealed record AxeEnum { // 私有字段存储数据,不生成公开属性 private readonly string _name; private readonly int _levelReq; private readonly int _itemId; // 私有构造函数,仅内部可创建实例 private AxeEnum(string name, int levelReq, int itemId) { _name = name; _levelReq = levelReq; _itemId = itemId; } // 内部访问方法,仅同一程序集内的Axe类可调用 internal string GetNameInternal() => _name; internal int GetLevelReqInternal() => _levelReq; internal int GetItemIdInternal() => _itemId; // 允许Axe类访问私有构造函数 public static class Factory { public static AxeEnum Create(string name, int levelReq, int itemId) => new AxeEnum(name, levelReq, itemId); } } static class Axe { static readonly Dictionary<int, AxeEnum> _axes = new(); static readonly AxeEnum _steel = AxeEnum.Factory.Create("Steel", 41, 1378); static Axe() { _axes.Add(GetId(_steel), _steel); } public static AxeEnum GetById(int id) { _axes.TryGetValue(id, out var axe); return axe; } // 扩展方法调用内部访问器获取数据 public static int GetLvlReq(this AxeEnum axe) => axe.GetLevelReqInternal(); public static int GetId(this AxeEnum axe) => axe.GetItemIdInternal(); public static string GetName(this AxeEnum axe) => axe.GetNameInternal(); }
优势:
- 对外暴露
AxeEnum类型,但无法直接访问其字段/属性 - 同一程序集内的扩展方法可通过内部访问器获取数据
- 私有构造函数确保只有指定代码能创建实例
为什么原代码无法实现需求?
你原代码中使用了位置式record,C#会自动为位置参数生成公开的只读属性(如Name、LevelReq),这就是外部能直接访问的原因。同时,扩展方法属于独立的静态类,无法访问其他类的私有成员,所以私有的privateField也无法被扩展方法读取。
内容的提问来源于stack exchange,提问作者Jess Chan
相关产品推荐
相关产品推荐

