缓存属性:更简单的方法?

时间:2010-04-05 15:50:08

标签: c# caching properties

我有一个对象,其属性的计算成本很高,因此它们仅在首次访问时计算,然后进行缓存。

 private List<Note> notes;
 public List<Note> Notes
    {
        get
        {
            if (this.notes == null)
            {
                this.notes = CalcNotes();
            }
            return this.notes;
        }
    }

我想知道,有更好的方法吗?是否有可能在C#中创建一个Cached属性或类似的东西?

8 个答案:

答案 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,则不会再缓存它。如果例如允许0NaN作为属性值,则同样使用值类型。

更好的是“面向方面”的解决方案,例如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();