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

重写的List属性调用父类方法?添加元素无效问题求解

问题

以下代码中调用Add方法后无任何效果,最终控制台无输出,原因是每次获取testProp都会返回新的过滤后列表,添加操作只作用于临时列表,未修改父类的底层列表:

internal class TestBase
{
    public virtual List<int> testProp { get; }
}

internal class Test : TestBase
{
    bool filteringLessThanZeroes = false;
    public override List<int> testProp 
    { 
        get => base.testProp.Where(i => filteringLessThanZeroes ? i > 0 : i >= 0).ToList(); 
    }
}

// 调用Add无效果
var test = new Test();
test.testProp.Add(0);
test.testProp.Add(23);
test.testProp.Add(22);

foreach (var item in test.testProp)
{
    Console.WriteLine(item); // 预期输出23、22,实际为空
}

需求:实现获取时过滤元素,但添加元素能生效的逻辑,且同一个属性需根据bool值切换过滤规则,该属性已被大量使用,不想大规模重构。

解决方案

当前思路的核心问题是每次get都返回新列表,导致修改操作无法作用到底层数据。正确的做法是用包装类继承List,让包装类的修改方法直接操作父类的底层列表,仅在查询/枚举时应用过滤逻辑,这样既兼容原有的List类型,又无需大规模修改调用代码。

完整实现代码

internal class TestBase
{
    public virtual List<int> testProp { get; }

    public TestBase()
    {
        // 父类必须初始化底层列表,避免null引用
        testProp = new List<int>();
    }
}

// 自定义过滤列表包装类,继承List<int>以兼容原有代码
internal class FilteredList : List<int>
{
    private readonly List<int> _sourceList;
    private readonly Func<int, bool> _filter;

    public FilteredList(List<int> source, Func<int, bool> filter)
    {
        _sourceList = source;
        _filter = filter;
    }

    // 修改类方法直接转发到底层列表
    public new void Add(int item) => _sourceList.Add(item);
    public new void Clear() => _sourceList.Clear();
    public new bool Remove(int item) => _sourceList.Remove(item);
    public new void RemoveAt(int index)
    {
        var filteredItem = _sourceList.Where(_filter).ElementAt(index);
        _sourceList.Remove(filteredItem);
    }

    // 查询类方法应用过滤逻辑
    public new IEnumerator<int> GetEnumerator() => _sourceList.Where(_filter).GetEnumerator();
    public new int Count => _sourceList.Count(_filter);
    public new int this[int index] => _sourceList.Where(_filter).ElementAt(index);
    public new bool Contains(int item) => _sourceList.Contains(item) && _filter(item);
}

internal class Test : TestBase
{
    public bool FilteringLessThanZeroes { get; set; } = false;
    private readonly FilteredList _filteredList;

    public Test()
    {
        // 绑定底层列表和过滤规则
        _filteredList = new FilteredList(base.testProp, item => 
            FilteringLessThanZeroes ? item > 0 : item >= 0);
    }

    // 返回包装类实例,而非新列表
    public override List<int> testProp => _filteredList;
}

// 测试代码
var test = new Test();
test.testProp.Add(0);
test.testProp.Add(23);
test.testProp.Add(22);

// 默认过滤规则:保留>=0的元素
foreach (var item in test.testProp)
{
    Console.WriteLine(item); // 输出:0、23、22
}

// 切换过滤规则:保留>0的元素
test.FilteringLessThanZeroes = true;
Console.WriteLine("开启过滤小于0后:");
foreach (var item in test.testProp)
{
    Console.WriteLine(item); // 输出:23、22
}

核心逻辑说明

  1. 包装类的作用:FilteredList继承自List<int>,完全兼容原有代码的调用方式,无需修改任何使用testProp的地方。
  2. 修改操作直接作用底层:Add、Clear等修改方法直接转发给父类的base.testProp,确保添加/删除操作能持久化到底层数据。
  3. 查询操作自动过滤:枚举元素、获取Count、索引器等查询操作会先应用过滤规则,返回符合条件的结果。
  4. 动态切换过滤规则:修改FilteringLessThanZeroes属性后,后续的查询操作会自动使用新的过滤条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:15:41