public 只读列表<T> 是糟糕的设计吗?
Is a public readonly List<T> bad design?
我目前正在编写一个应用程序,它与某种服务建立连接,以一些 DataTable
对象的形式获取数据,然后将其显示给用户。
为了存储我得到的数据,我做了一个名为 DataStorage
的 class,它有一个 List<DataTable>
。其他 classes 需要能够编辑此列表,例如添加需要的对象或在用户发现不需要时删除它们。我也必须能够清除它,我是否需要一组全新的数据。
我可以为此提供 DataStorage
方法,但由于 List<T>
已经提供了这些方法,所以我认为没有必要像那样封装它。所以我将其设置为 readonly
以确保没有人尝试分配新对象 - 甚至更糟,null
- 并设置了访问修饰符 public
.
这种设计是否可以接受,或者我应该始终保护字段不被直接访问,无论如何?
一般来说,您应该始终采用最通用的类型以减少任何紧密耦合并仅提供您实际需要访问的那些成员。话虽如此,在某些情况下,使用 ICollection
可能会更好,它提供对 Add
、Remove
和 Clear
等基本方法的访问。
然而,使集合 readonly
或更好的只获取 属性 可能是个好主意,没有什么可以反对的。
我们应该非常小心 public
这意味着 public
- 无论如何。
你让 class 有这样的行为吗?
public class Offender {
...
public void Offend(YourClass value) {
...
// In the middle of my routine I've ruined your class
value.Data.Clear();
value.Data.Add(someStuff);
...
}
}
我建议将 完全访问权限 限制为 Data
仅限受信任的 classes:
public class YourClass {
// Approved classes (i.e. from your routine) can write, delete, clear...
internal readonly List<Data> m_Data = new List<Data>();
// All the other can only read
public IReadOnlyList<Data> Data {
get {
return m_Data;
}
}
...
// If you let (in some cases) add, delete, clear to untrusted class
// just add appropriate methods:
public void Add(Data data) {
// Here you can validate the provided data, check conditions, state etc.
}
}
如果你想发布一个具有add/remove能力的合集,最好覆盖Collection<T>
(或ObservableCollection<T>
)class,非常类似于 List<T>
,但您可以覆盖并因此控制 add/remove/替换操作。是的,您可以通过 get-only 属性.
实现 public
public class MyClass
{
private MyCollection myCollection = new MyCollection();
public IList<MyElement> Collection { get { return myCollection; } }
}
internal class MyCollection: Collection<MyElement>
{
// by overriding InsertItem you can control Add and Insert
protected override InsertItem(int index, MyElement item)
{
if (CheckItem(item))
base.InsertItem(index, item);
throw new ArgumentException("blah");
}
// similarly, you can override RemoveItem to control Remove and RemoveAt,
// and SetItem to control the setting by the indexer (this[])
}
我目前正在编写一个应用程序,它与某种服务建立连接,以一些 DataTable
对象的形式获取数据,然后将其显示给用户。
为了存储我得到的数据,我做了一个名为 DataStorage
的 class,它有一个 List<DataTable>
。其他 classes 需要能够编辑此列表,例如添加需要的对象或在用户发现不需要时删除它们。我也必须能够清除它,我是否需要一组全新的数据。
我可以为此提供 DataStorage
方法,但由于 List<T>
已经提供了这些方法,所以我认为没有必要像那样封装它。所以我将其设置为 readonly
以确保没有人尝试分配新对象 - 甚至更糟,null
- 并设置了访问修饰符 public
.
这种设计是否可以接受,或者我应该始终保护字段不被直接访问,无论如何?
一般来说,您应该始终采用最通用的类型以减少任何紧密耦合并仅提供您实际需要访问的那些成员。话虽如此,在某些情况下,使用 ICollection
可能会更好,它提供对 Add
、Remove
和 Clear
等基本方法的访问。
然而,使集合 readonly
或更好的只获取 属性 可能是个好主意,没有什么可以反对的。
我们应该非常小心 public
这意味着 public
- 无论如何。
你让 class 有这样的行为吗?
public class Offender {
...
public void Offend(YourClass value) {
...
// In the middle of my routine I've ruined your class
value.Data.Clear();
value.Data.Add(someStuff);
...
}
}
我建议将 完全访问权限 限制为 Data
仅限受信任的 classes:
public class YourClass {
// Approved classes (i.e. from your routine) can write, delete, clear...
internal readonly List<Data> m_Data = new List<Data>();
// All the other can only read
public IReadOnlyList<Data> Data {
get {
return m_Data;
}
}
...
// If you let (in some cases) add, delete, clear to untrusted class
// just add appropriate methods:
public void Add(Data data) {
// Here you can validate the provided data, check conditions, state etc.
}
}
如果你想发布一个具有add/remove能力的合集,最好覆盖Collection<T>
(或ObservableCollection<T>
)class,非常类似于 List<T>
,但您可以覆盖并因此控制 add/remove/替换操作。是的,您可以通过 get-only 属性.
public class MyClass
{
private MyCollection myCollection = new MyCollection();
public IList<MyElement> Collection { get { return myCollection; } }
}
internal class MyCollection: Collection<MyElement>
{
// by overriding InsertItem you can control Add and Insert
protected override InsertItem(int index, MyElement item)
{
if (CheckItem(item))
base.InsertItem(index, item);
throw new ArgumentException("blah");
}
// similarly, you can override RemoveItem to control Remove and RemoveAt,
// and SetItem to control the setting by the indexer (this[])
}