C# 设计问题:使缓存的实体可变是好是坏?

C# 设计问题:使缓存的实体可变是好是坏?,c#,.net,design-patterns,caching,C#,.net,Design Patterns,Caching,这里我需要缓存一些实体,例如,内容管理系统(CMS)中的页面树。该系统允许开发人员编写插件,在插件中他们可以访问缓存的页面树。使缓存的页面树可变是好还是坏(即,有树节点对象的setter,和/或我们在ChildPages集合中公开Add,Remove方法。这样客户端代码就可以设置页面树节点的属性,并自由添加/删除树节点) 以下是我的观点: (1) 如果页面树是不可变的,插件开发人员就无法修改树。这样我们可以避免一些微妙的错误 (2) 但有时我们需要更改页面的名称。如果页面树是不可变的,我们应该调

这里我需要缓存一些实体,例如,内容管理系统(CMS)中的页面树。该系统允许开发人员编写插件,在插件中他们可以访问缓存的页面树。使缓存的页面树可变是好还是坏(即,有树节点对象的setter,和/或我们在ChildPages集合中公开Add,Remove方法。这样客户端代码就可以设置页面树节点的属性,并自由添加/删除树节点)

以下是我的观点:

(1) 如果页面树是不可变的,插件开发人员就无法修改树。这样我们可以避免一些微妙的错误

(2) 但有时我们需要更改页面的名称。如果页面树是不可变的,我们应该调用诸如“Refresh()”之类的方法来刷新缓存。这将导致数据库命中(因此总共两次数据库命中,但我们应该避免2次数据库命中中的1次)。在这种情况下,如果页面树是可变的,我们可以直接更改页面树中的名称,使其成为最新的(因此只需要一次数据库命中)

你觉得怎么样?如果遇到这种情况,你会怎么做

提前感谢!:)

更新:页面树类似于:

public class PageCacheItem {
    public string Name { get; set; }
    public string PageTitle { get; set; }
    public PageCacheItemCollection Children { get; private set; }
}
我这里的问题与hashcode无关,因为PageCacheItem不会作为键放在hashset或dictionary上

我的问题是:

如果PageCacheItem(树节点)是可变的,即属性有setter(例如,名称有setter,PageTitle属性有setter)。如果一些插件作者错误地更改了PageCacheItem的属性,系统将处于不正确的状态(缓存的数据与数据库中的数据不一致),并且这个错误很难调试,因为它是由一些插件引起的,而不是系统本身

但是如果PageCacheItem是只读的,那么可能很难实现高效的“缓存刷新”功能,因为没有属性设置器,我们不能简单地通过将属性设置为最新值来更新属性

更新2

谢谢各位。但我有一件事要注意,那就是,我不会开发一个通用的缓存框架,而是在现有缓存框架的基础上开发一些API。因此,我的API是底层缓存框架和插件作者之间的中间层。插件作者不需要知道任何关于底层缓存框架的信息。他只需要知道这个页面树是从缓存中检索到的。他得到了要使用的强类型PageCacheItem API,而不是从底层缓存框架检索到的弱类型“对象”


所以我的问题是关于为插件作者设计API的问题,也就是说,使API类PageCacheItem可变是好是坏(这里可变==属性可以在PageCacheItem类之外设置)?

这样看,如果条目是可变的,然后,当对象发生变化时,哈希代码很可能会发生变化

根据缓存的字典实现,它可以:

  • 迷路
  • 在最坏的情况下,需要重新缓存整个缓存
您想要“可变哈希代码”可能有一些合理的理由,但我看不出有什么理由。(在过去9年中,我只需要做一次)


只要删除并替换您希望“变异”的条目就会容易得多。

这样看,如果条目是可变的,那么当对象发生变异时,哈希代码很可能会发生变化

根据缓存的字典实现,它可以:

  • 迷路
  • 在最坏的情况下,需要重新缓存整个缓存
您想要“可变哈希代码”可能有一些合理的理由,但我看不出有什么理由。(在过去9年中,我只需要做一次)


删除和替换您希望“变异”的条目会容易得多。

首先,我假设您的意思是缓存的值可能是可变的,也可能不是可变的,而不是它所标识的标识符。如果你也指标识符,那么我会非常强调在这方面是不可变的(强调到足以让我的帖子标记为淫秽语言)

至于可变值,这里没有一个正确的答案。您已经了解了主要的正反两种方法,并且在您描述的两个选项中都有多个变体。缓存失效通常是一个众所周知的难题(正如菲尔·卡尔顿(Phil Karlton)的名言“计算机科学中只有两个难题:缓存失效和命名问题”。*)

需要考虑的一些事项:

  • 多久进行一次更改。如果更改很少,刷新变得很容易-转储现有缓存并让它重新生成
  • CMS是否会在多台服务器上,或者将来是否会,因为这意味着必须共享任何失效信息
  • 过时的数据有多糟糕,多久就坏了(您可以在接下来的一小时左右愉快地为过时的值提供服务器,或者这会与新值发生灾难性的冲突)
  • 重新验证方法对您有意义吗?在特定时间后,检查缓存值以确保其仍然有效,并更新到下一次检查的时间(或者,定期转储旧值,让它们再次从新源检索)
  • 首先,检测陈旧性有多容易?如果很难做到这一点,可能会排除某些方法
  • 缓存实际节省了多少。你能把它扔掉吗
  • 我没有提到线程问题,因为线程问题对于任何类型的缓存都很困难,除非您是单线程的(如果是CMS,我猜是web,因此本质上是多线程的)