我和一个朋友(都是编程新手)都在争论在包含该类所有实例的类中包含一个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);
}
}
答案 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 :
优点:无
缺点:
跟踪类的实例不是类的责任(请参见SRP)
非线程安全(请参阅ConcurrentDictionary)
B :
优点:
缺点:
如上所述,如果您需要缓存某些项目,请使用MemoryCache。