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

C#构造函数传成员访问函数报静态上下文访问非静态属性错误如何解决

问题根因

C#规范明确禁止在父类构造器的调用参数中访问当前实例的非静态成员:父类构造器的执行时机早于子类实例成员初始化、子类构造器主体执行,编译器默认该场景下访问实例成员存在未初始化风险,哪怕你明确委托只会在构造完成后调用,编译器也不会放行。

可行解决方案

方案1:改造父类暴露集合属性,消除子类冗余字段(最推荐)

不需要在子类单独声明集合字段,直接在父类Selection中存储集合实例或对外暴露受保护的集合访问属性,完全消除样板代码:

public class Selection<T, W> : ISelection<T,W> where W : ICollection<T>
{
    // 新增受保护属性,供子类直接操作集合
    protected W Items { get; }

    public Selection(Func<W> selectableItemsProvider)
    {
        // 若确定构造完成后才会调用委托,也可以延迟求值,这里按实际需求调整
        Items = selectableItemsProvider();
        // 原有构造逻辑保持不变
    }
}

子类实现可简化为:

public class MyFoo : Selection<Blah, List<Blah>>
{
    public MyFoo() : base(() => new List<Blah>())
    {
        // 子类操作集合直接调用基类的Items属性即可
        Items.Add(new Blah());
    }
}

方案2:用懒加载绕过编译器静态检查

如果确实需要在子类单独持有集合引用,可以用Lazy<T>包装集合,避免直接在父类构造参数中访问实例成员:

public class MyFoo : Selection<Blah, List<Blah>>
{
    // 懒加载对象的初始化时机早于父类构造调用,不会触发报错
    private readonly Lazy<List<Blah>> _blahs = new(() => new List<Blah>());

    public MyFoo() : base(() => _blahs.Value)
    {
        // 后续操作集合直接访问_blahs.Value即可
    }
}

方案3:调整父类初始化逻辑,子类构造内赋值委托

如果不想修改原有父类构造的调用逻辑,可以新增受保护的无参构造和可写的委托属性,在子类构造主体中完成委托赋值:

public class Selection<T, W> : ISelection<T,W> where W : ICollection<T>
{
    protected Func<W> SelectableItemsProvider { get; set; }

    // 新增受保护无参构造,仅供子类调用
    protected Selection() {}

    public Selection(Func<W> selectableItemsProvider)
    {
        SelectableItemsProvider = selectableItemsProvider;
        // 原有构造逻辑保持不变
    }
}

子类实现:

public class MyFoo : Selection<Blah, List<Blah>>
{
    private List<Blah> _blahs = new List<Blah>();

    public MyFoo() : base()
    {
        // 子类构造主体执行时实例已完成初始化,可以正常赋值委托
        SelectableItemsProvider = () => _blahs;
        // 原有构造逻辑保持不变
    }
}

内容的提问来源于stack exchange,提问作者User1291

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 22:36:03