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

为何List<T>属性的编辑方法仅调用get访问器?如何解决?

问题解答

为什么Add/Remove不触发set访问器?

List<T>是引用类型,调用属性的get访问器时,返回的是该List对象的引用。Add()、Remove()这类方法只是通过这个引用修改List内部的元素集合,并没有改变属性本身指向的引用(也就是没有给属性赋值新的List实例)。而set访问器只有在给属性赋新值时才会触发,比如MyList = new List<T>()这种场景。

解决方案

结合你的接口约束,提供几种可行方案:

方案1:自定义集合类封装同步逻辑

如果接口允许将属性类型改为IList<T>(而非硬要求List<T>),可以自定义实现IList<T>的集合类,在所有修改集合的方法中加入数据库同步逻辑:

public class DbSyncList<T> : IList<T>
{
    private readonly List<T> _innerList = new List<T>();

    public void Add(T item)
    {
        _innerList.Add(item);
        // 执行数据库插入逻辑
        SyncToDatabase();
    }

    public bool Remove(T item)
    {
        var removed = _innerList.Remove(item);
        if (removed)
        {
            // 执行数据库删除逻辑
            SyncToDatabase();
        }
        return removed;
    }

    // 实现IList<T>的其他成员(如Indexer、Insert、Clear等),按需加入同步逻辑
    // ...

    private void SyncToDatabase()
    {
        // 你的数据库更新代码
    }
}

在你的实现类中返回这个自定义集合,其他不需要同步的实现类直接返回普通List<T>即可(因为List<T>也实现了IList<T>):

public class YourClass : IYourInterface
{
    public IList<T> YourList { get; set; } = new DbSyncList<T>();
}

方案2:用ObservableCollection订阅变更事件

如果接口可改为IList<T>,可以使用ObservableCollection<T>,它会在集合元素变更时触发CollectionChanged事件,你只需订阅该事件并同步数据库:

public class YourClass : IYourInterface
{
    private ObservableCollection<T> _yourList;

    public IList<T> YourList 
    { 
        get => _yourList;
        set
        {
            if (_yourList != null)
            {
                _yourList.CollectionChanged -= OnListChanged;
            }
            _yourList = value as ObservableCollection<T> ?? new ObservableCollection<T>(value);
            _yourList.CollectionChanged += OnListChanged;
            // 赋值新集合时可同步全量数据
            SyncToDatabase();
        }
    }

    private void OnListChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // 根据变更类型(添加、删除等)执行对应数据库操作,也可通过e.NewItems/e.OldItems做精细处理
        SyncToDatabase();
    }

    private void SyncToDatabase()
    {
        // 你的数据库更新逻辑
    }
}

其他实现类依旧返回List<T>,赋值时会自动被包装为ObservableCollection<T>。

方案3:封装操作方法,限制直接修改集合

如果接口必须保持List<T>类型且无法修改,可将属性设为只读,在类中提供专门的添加/删除方法,在方法内操作集合并同步数据库:

public class YourClass : IYourInterface
{
    private readonly List<T> _yourList = new List<T>();

    // 返回只读包装,阻止外部直接调用修改方法
    public List<T> YourList => _yourList.AsReadOnly() as List<T>;

    public void AddItem(T item)
    {
        _yourList.Add(item);
        SyncToDatabase();
    }

    public void RemoveItem(T item)
    {
        if (_yourList.Remove(item))
        {
            SyncToDatabase();
        }
    }

    private void SyncToDatabase()
    {
        // 数据库更新逻辑
    }
}

注:AsReadOnly()的强制转换虽不严谨,但能避免大部分非恶意的直接修改;若接口允许,改为返回IReadOnlyList<T>会更规范。

接口兼容建议

如果接口硬要求List<T>,方案3是最直接的选择;若可将接口属性类型改为IList<T>,方案1或2会更优雅,既能满足同步需求,也不影响其他实现类使用普通List<T>。

内容的提问来源于stack exchange,提问作者just-a-hriday

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 23:17:11