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

如何通过扩展方法暴露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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 16:10:56