繁体   English   中英

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

[英]Cached Property: Easier way?

我有一个对象的属性计算起来很昂贵,所以它们只在第一次访问时计算然​​后缓存。

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

我想知道,有没有更好的方法来做到这一点? 是否有可能在 C# 中创建缓存属性或类似的东西?

就语法而言,如果您想花哨,可以使用空合并运算符,但它不一定具有可读性。

get
{
    return notes ?? (notes = CalcNotes());
}

编辑:更新礼貌马修。 另外,我认为其他答案对提问者更有帮助!

在 .NET 3.5 或更早版本中,您拥有的是一个非常标准的实践和一个很好的模型。

(虽然,我会建议返回IList<T>IEnumerable<T>如果可能的话,而不是List<T>的公共API中- 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);

对我来说看起来很标准。 你在做什么很好。

问题是?? 是如果CalcNotes()返回null那么它将不再被缓存。 如果例如0NaN都允许作为属性值,则值类型同上。

更好的是“面向方面”的解决方案,例如Post - Sharp使用属性然后修改 MSIL(字节码)。

代码如下所示:

[Cached]
public List<Note> Notes { get { return CalcNotes(); } }

编辑: CciSharp.LazyProperty.dll正是这样做的!!!

是的,这是可能的。 问题是,这样做你赢了多少——你仍然需要在某处初始化代码,所以你最多只能保存条件表达式。

不久前,我实现了一个类来处理这个问题。 您可以在这个问题中找到发布的代码,我在那里询问这是否是一个好主意。 答案中有一些有趣的意见,请务必在决定使用之前阅读所有内容。

编辑:

一个Lazy<T> 类与我上面链接的实现基本相同,已添加到 .NET 4 框架中; 因此,如果您使用的是 .NET 4,则可以使用它。请参见此处的示例: http : //weblogs.asp.net/gunnarpeipman/archive/2009/05/19/net-framework-4-0-using-system-懒人-lt-t-gt.aspx

如果该值难以计算,我通常更喜欢使用方法 ( GetNotes() )。 没有什么可以阻止您使用方法缓存值,此外,如果适用,您可以添加[Pure]属性 (.NET 4) 以指示该方法不会改变对象的状态。

如果您确实决定保留以下内容,我建议:

每当您有一个延迟评估的属性时,您应该添加以下属性以确保在调试器中运行的行为与在调试器之外运行的行为相同:

[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; }
}

问题是陈旧的,但这是你在2019年的表现 - 默认值的自动属性(C#6.0及更高版本)

public List<Note> Notes { get; private set; } = CalcNotes();

带有 C# 8 和空合并赋值的两行选项:

private List<Note>? notes;
public List<Note> Notes => notes ??= CalcNotes();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM