我有一个对象,其属性的计算成本很高,因此它们仅在首次访问时计算,然后进行缓存。
private List<Note> notes;
public List<Note> Notes
{
get
{
if (this.notes == null)
{
this.notes = CalcNotes();
}
return this.notes;
}
}
我想知道,有更好的方法吗?是否有可能在C#中创建一个Cached属性或类似的东西?
答案 0 :(得分:22)
就语法而言,如果您想要使用null-coalescing运算符,可以使用{{3}}运算符,但它不一定是可读的。
get
{
return notes ?? (notes = CalcNotes());
}
编辑:更新了Matthew的礼貌。另外,我认为其他答案对提问者更有帮助!
答案 1 :(得分:20)
在.NET 3.5或更早版本中,您拥有的是非常标准的练习和精细的模型。
(尽管我建议在可能的情况下返回IList<T>
或IEnumerable<T>
,而不是在您的公开API中List<T>
- List<T>
应该是一个实施细节...... )
但是,在.NET 4中,这里有一个更简单的选项:Lazy<T>
。这可以让你:
private Lazy<IList<Note>> notes;
public IEnumerable<Note> Notes
{
get
{
return this.notes.Value;
}
}
// In constructor:
this.notes = new Lazy<IList<Note>>(this.CalcNotes);
答案 2 :(得分:6)
??
的问题是,如果CalcNotes()
返回null
,则不会再缓存它。如果例如允许0
和NaN
作为属性值,则同样使用值类型。
更好的是“面向方面”的解决方案,例如Post - Sharp使用属性然后修改MSIL(字节码)。
代码如下:
[Cached]
public List<Note> Notes { get { return CalcNotes(); } }
编辑: CciSharp.LazyProperty.dll正是这样!!!
答案 3 :(得分:4)
对我来说非常标准。你做得很好。
答案 4 :(得分:2)
这个问题很旧,但是这是您在2019年的操作方式-具有默认值(C#6.0和更高版本)的自动属性
public List<Note> Notes { get; private set; } = CalcNotes();
答案 5 :(得分:1)
是这是可能的。问题是,通过这样做你赢了多少 - 你仍然需要在某个地方使用初始化代码,所以最多你将保存条件表达式。
前段时间我实现了一个类来处理这个问题。您可以找到this question中发布的代码,我会问这是不是一个好主意。答案中有一些有趣的意见,请务必在决定使用它们之前阅读它们。
与我上面链接的实现基本相同的Lazy<T> class已添加到.NET 4 Framework中;因此,如果您使用的是.NET,则可以使用它。请参阅此处的示例:http://weblogs.asp.net/gunnarpeipman/archive/2009/05/19/net-framework-4-0-using-system-lazy-lt-t-gt.aspx
答案 6 :(得分:1)
如果计算值非常重要,我通常更喜欢使用方法(GetNotes()
)。没有什么可以阻止您使用方法缓存值,此外,如果适用,您可以添加[Pure]
属性(.NET 4)以指示方法不会更改对象的状态。
如果您决定继续使用以下内容,我建议:
每当你有一个lazily-evaluated属性时,你应该添加以下属性,以确保在调试器中运行的行为与在其外运行相同:
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
此外,从.NET 4开始,您可以使用以下内容:
// the actual assignment will go in the constructor.
private readonly Lazy<List<Note>> _notes = new Lazy<List<Note>>(CalcNotes);
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public List<Note> Notes
{
get { return _notes.Value; }
}
答案 7 :(得分:0)
带有C#8和null-coalescing assignment的两行选项:
private List<Note>? notes;
public List<Note> Notes => notes ??= CalcNotes();