Cached Property: Easier way?

前端 未结 7 2011
傲寒
傲寒 2021-01-01 10:00

I have a object with properties that are expensive to compute, so they are only calculated on first access and then cached.

 private List notes;
         


        
相关标签:
7条回答
  • 2021-01-01 10:30

    If the value is non-trivial to compute, I generally prefer using a method (GetNotes()). There's nothing stopping you from caching the value with a method, plus you can add the [Pure] attribute (.NET 4) if applicable to indicate the method does not alter the state of the object.

    If you do decide to stay with the following, I recommend:

    Whenever you have a lazily-evaluated property, you should add the following attribute to ensure that running in the debugger behaves the same as running outside of it:

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    

    Also, starting with .NET 4, you can use the following:

    // 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; }
    }
    
    0 讨论(0)
  • 2021-01-01 10:38

    Yes it is possible. The question is, how much you are winning by doing it - you still need the initialization code somewhere, so at most you will be saving the conditional expression.

    A while ago I implemented a class to handle this. You can find the code posted in this question, where I ask whether it's a good idea. There are some interesting opinions in the answers, be sure to read them all before deciding to use it.

    Edit:

    A Lazy<T> class that does basically the same as my implementation that I link to above, has been added to the .NET 4 Framework; so you can use that if you are on .NET 4. See an example here: http://weblogs.asp.net/gunnarpeipman/archive/2009/05/19/net-framework-4-0-using-system-lazy-lt-t-gt.aspx

    0 讨论(0)
  • 2021-01-01 10:40

    As far as syntax goes, you can use the null-coalescing operator if you want to be fancy, but it's not necessarily as readable.

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

    Edit: Updated courtesy of Matthew. Also, I think the other answers are more helpful to the question asker!

    0 讨论(0)
  • 2021-01-01 10:43

    Looks pretty standard to me. What you are doing is fine.

    0 讨论(0)
  • 2021-01-01 10:47

    In .NET 3.5 or earlier, what you have is a very standard practice, and a fine model.

    (Although, I would suggest returning IList<T>, or IEnumerable<T> if possible, instead of List<T> in your public API - List<T> should be an implementation detail...)

    In .NET 4, however, there is a simpler option here: Lazy<T>. This lets you do:

    private Lazy<IList<Note>> notes;
    public IEnumerable<Note> Notes
    {
        get
        {
            return this.notes.Value;
        }
    }
    
    // In constructor:
    this.notes = new Lazy<IList<Note>>(this.CalcNotes);
    
    0 讨论(0)
  • The problem with ?? is that if CalcNotes() returns null then it will not be cached any more. Ditto for value types if for example both 0 and NaN are allowed as property value.

    Much better would be an "aspect-oriented" solution, something like Post-Sharp does using attributes and then modifying MSIL (bytecode).

    The code would look like:

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

    EDIT: CciSharp.LazyProperty.dll does exactly this!!!

    0 讨论(0)
提交回复
热议问题