是否有更简单的方法来获得只能在同一个类中修改的 ObservableCollection?

问题描述 投票:0回答:1

我通常需要一个只读的 ObservableCollection (以便它的引用或内容只能在此类中修改)。我需要 ObservableCollection,因为我将使用 WPF 绑定到该属性(下面的代码中未显示)。这是一个完全可复制的工作示例,显示了我的意图:

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");        //-> should work
        Debug.Print(myClass.Values[0]); //-> should work
        myClass.Values = new();         //-> should NOT work
        myClass.Values.Add("192");      //-> should NOT work
    }
}

我从这里得到了这个图案。

但是,这需要为每个公共集合编写大量代码 - 构造函数中需要两个附加字段和两行代码。如果我的类中需要很多这样的集合,它就会很快膨胀,从而损害代码的可读性。

鉴于我链接的解决方案已经有 14 年历史了,有什么方法可以用更少的代码实现相同的功能,最好没有额外的字段,并且构造函数中什么也没有?是否可以定义我自己的派生类来抽象此行为?理想的声明和使用应该是这样的:

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");        //-> should work
        Debug.Print(myClass.Values[0]); //-> should work
        myClass.Values = new();         //-> should NOT work
        myClass.Values.Add("192");      //-> should NOT work
    }
}

如果不可能实现这一目标,我可以在这里做的下一个最好的事情是什么?

c# observablecollection
1个回答
0
投票

您想做这样的事情,按文档顺序初始化您的成员:

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

但是你不能,因为你会得到编译错误

A field initializer cannot reference the non-static field, method, or property 'MyClass._values'

此错误在 编译器错误 CS0236 中进行了解释:

实例字段不能用于初始化方法之外的其他实例字段

相反,您可以使用字段来初始化构造函数内的其他字段。 您没有提及您正在使用的 C# 版本,但由于您使用的是目标类型 new(),您正在使用

C# 9.0
或更高版本,并且可以执行以下操作: public class MyClass { private readonly ObservableCollection<string> _values; // Initialize in the constructor public ReadOnlyCollection<string> Values { get; } // Initialize in the constructor public MyClass() => this.Values = new(_values = new());

通过使用 lambda 语法,这只需要比未编译的所需最小语法多一行。

演示

这里

在 .NET Framework 中,某些语法糖不可用。 那时我们需要做:
public class MyClass { private readonly ObservableCollection<string> _values; public ReadOnlyCollection<string> Values { get; private set; } public MyClass() { this.Values = new ReadOnlyCollection<string>(_values = new ObservableCollection<string>()); }
演示小提琴 #2 
这里

© www.soinside.com 2019 - 2024. All rights reserved.