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

如何简化仅类内部可修改的ObservableCollection实现?

问题

我经常需要一种仅能在类内部修改引用或内容的ReadOnly ObservableCollection,因为要用于WPF绑定,所以必须基于ObservableCollection实现。当前的方案需要两个私有字段加构造器代码,要是多个这类集合的话会让代码变得臃肿,可读性下降。

现有实现示例

public class MyClass
{ 
    public ReadOnlyCollection<string> Values { get { return _valuesRO; } }

    private readonly ObservableCollection<string> _values;
    private readonly ReadOnlyObservableCollection<string> _valuesRO;

    public MyClass()
    {
        _values = new();
        _valuesRO = new(_values);
    }

    public void AddValue(string value)
    {
        _values.Add(value + ":");
    }
}

public static class MyApp
{
    public static void Main()
    {
        MyClass myClass = new();

        myClass.AddValue("192");        //-> 应正常执行
        Debug.Print(myClass.Values[0]); //-> 应正常执行
        myClass.Values = new();         //-> 不应允许执行
        myClass.Values.Add("192");      //-> 不应允许执行
    }
}

这个方案已经用了14年,现在想找更简洁的实现:不需要额外字段和构造器代码,只用一句声明初始化,比如自定义MySpecialReadOnlyCollection类,理想实现如下:

理想实现示例

public class MyClass
{ 
    public MySpecialReadOnlyCollection<string> Values { get; init; } = new();

    public void AddValue(string value)
    {
        Values.Add(value + ":");
    }
}

public static class MyApp
{
    public static void Main()
    {
        MyClass myClass = new();

        myClass.AddValue("192");        //-> 应正常执行
        Debug.Print(myClass.Values[0]); //-> 应正常执行
        myClass.Values = new();         //-> 不应允许执行
        myClass.Values.Add("192");      //-> 不应允许执行
    }
}

如果没法实现这种理想方案,请问次优方案是什么?核心需求是无集合后备字段和构造器代码,提升可扩展性,主要目的是明确代码意图、避免意外修改,不用考虑反射这类非常规修改的安全性。


解决方案

理想方案的可行实现

通过自定义封装类可以实现接近理想的效果,核心思路是让集合对外暴露只读接口,内部保留修改能力:

自定义MySpecialReadOnlyCollection类

public class MySpecialReadOnlyCollection<T> : ReadOnlyObservableCollection<T>
{
    private readonly ObservableCollection<T> _innerCollection;

    // 内部构造器,限制仅同程序集内创建实例
    internal MySpecialReadOnlyCollection() : base(new ObservableCollection<T>())
    {
        _innerCollection = (ObservableCollection<T>)Items;
    }

    // 内部暴露修改方法,仅同程序集内可调用
    internal void Add(T item) => _innerCollection.Add(item);
    internal void Remove(T item) => _innerCollection.Remove(item);
    internal void Clear() => _innerCollection.Clear();
    // 按需添加其他需要的修改方法
}

使用示例

public class MyClass
{ 
    public MySpecialReadOnlyCollection<string> Values { get; init; } = new();

    public void AddValue(string value)
    {
        // 同程序集内可直接调用internal修改方法
        Values.Add(value + ":");
    }
}

该实现完全满足需求:

  • 外部仅能看到ReadOnlyObservableCollection的只读成员,无法调用修改方法
  • 内部无需额外字段,只用一句声明完成初始化
  • 外部无法重新赋值Values(依赖init访问器)

如果需要跨程序集使用,可将构造器和修改方法标记为protected internal,或确保业务类与自定义集合处于同一程序集。

次优方案:简化现有模式

如果不想自定义集合类,可以用C#的语法特性精简原有实现,去掉构造器冗余代码:

public class MyClass
{ 
    private readonly ObservableCollection<string> _values = new();
    public ReadOnlyObservableCollection<string> Values { get; } = new(_values);

    public void AddValue(string value)
    {
        _values.Add(value + ":");
    }
}

这个方案将字段初始化直接放在声明处,省去了构造器代码,虽然仍保留私有字段,但代码简洁度和可读性大幅提升,是原有模式的最优精简版本。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 07:57:19