Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 是一个公共只读列表<;T>;糟糕的设计?_C#_Oop_Software Design - Fatal编程技术网

C# 是一个公共只读列表<;T>;糟糕的设计?

C# 是一个公共只读列表<;T>;糟糕的设计?,c#,oop,software-design,C#,Oop,Software Design,我目前正在编写一个应用程序,它建立与某种服务的连接,以一些DataTable对象的形式获取数据,然后向用户显示数据。 为了存储我得到的数据,我创建了一个名为DataStorage的类,它有一个列表。其他类需要能够编辑此列表,例如添加所需的对象,或者在用户发现不必要时删除它们。如果我需要一组全新的数据,我还必须能够清除它。 我可以为它提供DataStorage方法,但是由于List已经提供了这些方法,我认为这样封装它没有任何意义。因此,我将其设置为只读,以确保没有人尝试分配新对象,或者更糟糕的是,

我目前正在编写一个应用程序,它建立与某种服务的连接,以一些
DataTable
对象的形式获取数据,然后向用户显示数据。
为了存储我得到的数据,我创建了一个名为
DataStorage
的类,它有一个
列表
。其他类需要能够编辑此列表,例如添加所需的对象,或者在用户发现不必要时删除它们。如果我需要一组全新的数据,我还必须能够清除它。
我可以为它提供
DataStorage
方法,但是由于
List
已经提供了这些方法,我认为这样封装它没有任何意义。因此,我将其设置为
只读
,以确保没有人尝试分配新对象,或者更糟糕的是,
null
,并将访问修饰符
设置为公共


这种设计可以接受吗?或者我应该始终保护字段不被直接访问吗?

一般来说,您应该始终采用最通用的类型,以减少任何紧耦合,并仅提供您实际需要访问的成员。话虽如此,在某些情况下,最好使用
i集合
,它提供对基本方法的访问,如
添加
删除
清除


但是,将集合设置为只读或更好的Get only属性可能是一个好主意,对此无可厚非。

我们应该非常小心
public
,这意味着
public
-无论什么。 你让任何一个班级有这样的行为吗

  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);
      ...
    }
  }
我建议将对
数据的完全访问权限限制为仅受信任的类:

  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.
    }
  }
公共类您的类{
//已批准的类(即来自您的例程)可以写入、删除、清除。。。
内部只读列表m_Data=new List();
//其他人都只能阅读
公共IReadOnlyList数据{
得到{
返回m_数据;
}
}
...
//如果允许(在某些情况下)添加、删除、清除不受信任的类
//只需添加适当的方法:
公共作废添加(数据){
//在这里,您可以验证提供的数据、检查条件、状态等。
}
}

如果要发布具有添加/删除功能的集合,最好覆盖
集合
(或
ObservableCollection
)类,该类与
列表
非常类似,但您可以覆盖并控制添加/删除/替换操作。是的,您可以通过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[])
}
公共类MyClass
{
私有MyCollection MyCollection=新MyCollection();
公共IList集合{get{return myCollection;}}
}
内部类MyCollection:集合
{
//通过重写InsertItem,可以控制添加和插入
受保护的重写插入项(int索引,MyElement项)
{
如果(检查项目(项目))
基本插入项(索引,项目);
抛出新的ArgumentException(“废话”);
}
//同样,您可以覆盖RemoveItem以控制Remove和RemoveAt,
//和SetItem控制索引器的设置(此[])
}

我建议将其声明为
内部
,而不是
公共
:某些(已批准的)类可以编辑列表,但不能编辑任何人。您不需要跟踪添加和删除吗?
列表
不是线程安全的。这会给你带来问题吗?@Damien_不信者不,我不会。@Enigmatity线程安全对我来说是个未知的术语。Wikipedia将它定义为一段线程安全的代码,如果它只以保证多个线程同时安全执行的方式操作共享数据结构。由于这只是一个显示一些数据的小工具,我不认为多线程是一个问题。同意,它应该作为
ICollection
公开。它也应该通过一个属性而不是一个裸露的字段公开。因此,因为我基本上只需要我们提到的三种方法,拥有我的存储工具<代码> IcLeopys<代码>比一个公开的<代码>列表<代码>更简单,因为<代码>清单>代码>提供了很多我不需要的东西。从技术上讲,您可能希望更改类内部保存对象的方式。如果其他类需要一个列表,那么此时必须重写所有这些类。然而,如果他们只是期望一个ICollection,您可以切换到任何其他ICollection而不影响任何其他类,并且即使您实现了自己的解决方案,您也只需要实现ICollection,而不是创建List的子类。这是始终坚持最通用的界面的一个很好的理由。@Tobberoth你是对的,我倾向于忘记这一点。谢谢你的提醒。在我的情况下,将其内部化不会有多大区别,因为我这里只有一个组件。不过,对于更大的项目,您是完全正确的,非常感谢您的时间。您应该附加该属性,以便更改内部列表中的元素,您可以创建一些在该列表上工作的包装器方法。我知道我可以使用get only属性,但在这种特殊情况下,它现在为我带来了好处。但这是一段非常有趣的代码,在将来可能会很有用。