类内对象的列表或字典

时间:2019-04-29 07:07:38

标签: c# list dictionary

我和一个朋友(都是编程新手)都在争论在包含该类所有实例的类中包含一个Dictionary是否明智。

我说字典最好在主目录而不是在类本身。

我没有充分的理由说出为什么,但是我从未见过有类记录已创建对象的记录。

您能给我每种方法的利弊吗?

谢谢。

A:

    class Table
    {
      public static Dictionary<int,Table> Tables = new Dictionary<int, Table>();
     ...
     public table (int ID)  // constructor
     {
      ...
      Tables.Add(ID,this);
     }   
    }

B:

     class Program
     {
      public Dictionary<int,Table> Tables = new Dictionary<int, Table>();
      static void Main(string[] args)
      {
       ...
       Table A = new Table (10);
       Tables.Add(10,A);
       }
      }

5 个答案:

答案 0 :(得分:5)

这主要取决于您的需求和您的架构/设计偏好。

在类中包含字典可以使所有与类相关的逻辑得到很好的封装。这样,您可以向类用户隐藏(静态)字典,并由您的类在内部对其进行管理。

将字典置于类之外会使该机制在其他方面具有灵活性。例如,您可以为您的类实例管理多个不同的字典(出于多种目的)。或者,如果您在特定的解决方案环境中不需要这样的字典,也可以将其丢掉。

恕我直言,没有严格的准则可以告诉您您是否应该做特定的事情。只要有创造力。只要最终结果清晰,可维护,可扩展等,天空就是极限。

答案 1 :(得分:4)

嗯,A版本意味着您不能同时拥有两个Table两个 ID

using System.Collections.Concurrent;

...

public class Table {
  //DONE: Do not expose fields but readonly properties 
  //DONE: Keep static (i.e. global) members (fields, properties, methods) being thread safe
  private static ConcurrentDictionary<int, Table> s_Tables = 
    new ConcurrentDictionary<int, Table>();

  public Table(int ID) { 
    s_Tables.Add(ID, this);
  }

  //DONE: All we expose is thead safe read-only version of the dictionary
  public static IReadOnlyDictionary<int, Table> Tables = s_Tables;
}

B版本意味着您可以拥有多个Program时,每个人都有自己的Table,这就是ID并非全球唯一的原因:

public class Program {
  //DONE: Do not expose fields but readonly properties 
  private Dictionary<int,Table> m_Tables = new Dictionary<int, Table>();

  public Program() {
    Table A = new Table (10);
    m_Tables.Add(10,A); 

    ...
  }

  //DONE: All we expose is read-only version of the dictionary
  public IReadOnlyDictionary<int, Table> Tables = m_Tables; 
}

...

//DONE: please, do not cram all the logic into `Main`, 
//      have a special classes business logic (Program) and entry point
public static class EntryPoint {
  static void Main(string[] args) {
    Program program = new Program();

    ...
  }
}

由于在您的原始代码中,static void Main类中的Program是有效的 singleton ,所以似乎A版本更可取:关于{{ 1}}属于Table类;您不能偶尔创建具有相同Table的{​​{1}}的第二个实例

答案 2 :(得分:1)

方法A.如果应跟踪类的所有实例,则它应该是该类的自动功能,可以使用静态字典来实现。该字典应该是私有的,以便其他类不能对其进行修改。这样可以保证字典是正确的。

但是,对于初学者来说,这不是一个好方法,因为它可以防止垃圾回收清除对象。这意味着您必须手动决定何时释放对象,以及何时将其从字典中删除。您可以为此实现iDisposable接口。通常最好与它一起使用using块,但是有时您将需要找到另一种方法来管理对象的生存期。

方法B对于小型程序来说很好,但是它也没有任何优点。在较大的程序中,将难以管理并且容易出错。您可能会忘记添加对象,或者您可能有一些代码错误地添加或删除了对象,或者某些代码可能假定在删除对象时存在对象,等等。

答案 3 :(得分:1)

任何概念都没错。您必须决定缓存是设计的一部分(A)还是用户层的选择(B)。

如果它是内置功能,我将略微修改方法A:

public class Table
{
    // cache is private so it cannot be manipulated from outside
    private static Dictionary<int,Table> tables = new Dictionary<int, Table>();

    // constructor is private so Table can be created by the GetTable factory method
    private Table(int id)
    {
        //...
    }

    // the factory method that transparently returns the table either from cache or by creating one
    public static Table GetTable(int id)
    {
         if (tables.TryGetValue(id, out Table result))
             return result;
         result = new Table(id);
         tables[id] = result;
         return result;
    }
}

答案 4 :(得分:1)

A
优点:无
缺点

B
优点

  • 类不承担超出其范围的超额责任

缺点

  • “跟踪”代码应封装到单独的类中,这些类负责创建实例,跟踪实例,管理时间策略等(factory可能适用)
  • 非线程安全

如上所述,如果您需要缓存某些项目,请使用MemoryCache