Кэшированное свойство: проще? - PullRequest
35 голосов
/ 05 апреля 2010

У меня есть объект со свойствами, которые дороги для вычисления, поэтому они рассчитываются только при первом доступе, а затем кэшируются.

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

Интересно, есть ли лучший способ сделать это? Возможно ли как-то создать Cached Property или что-то подобное в C #?

Ответы [ 7 ]

22 голосов
/ 05 апреля 2010

Что касается синтаксиса, вы можете использовать оператор null-coalescing , если хотите быть необычным, но он не обязательно так удобен для чтения.

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

Редактировать: Обновлено любезно предоставлено Мэтью. Кроме того, я думаю, что другие ответы более полезны для задающего вопрос!

20 голосов
/ 05 апреля 2010

В .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);
6 голосов
/ 12 июля 2010

Проблема с ?? заключается в том, что если CalcNotes() возвращает null, то оно больше не будет кэшироваться. То же самое для типов значений, если, например, оба значения 0 и NaN допустимы в качестве значения свойства.

Гораздо лучше было бы «аспектно-ориентированное» решение, например, Post - Sharp использует атрибуты и затем изменяет MSIL (байт-код).

Код будет выглядеть так:

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

РЕДАКТИРОВАТЬ: CciSharp.LazyProperty.dll делает именно это !!!

4 голосов
/ 05 апреля 2010

Выглядит довольно стандартно для меня. То, что вы делаете, прекрасно.

2 голосов
/ 27 февраля 2019

Вопрос старый, но вот как это сделать в 2019 году - автоматические свойства со значениями по умолчанию (C # 6.0 и выше)

public List<Note> Notes { get; private set; } = CalcNotes();
1 голос
/ 05 апреля 2010

Если значение нетривиально для вычисления, я обычно предпочитаю использовать метод (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; }
}
1 голос
/ 05 апреля 2010

Да возможно. Вопрос в том, сколько вы выигрываете, делая это - вам все еще нужен где-то код инициализации, так что в большинстве случаев вы будете сохранять условное выражение.

Некоторое время назад я реализовал класс для обработки этого. Вы можете найти код, размещенный в этом вопросе , где я спрашиваю, хорошая ли это идея. В ответах есть несколько интересных мнений, обязательно прочитайте их все, прежде чем принять решение использовать его.

Edit:

A Ленивый класс , который в основном соответствует моей реализации, на которую я ссылаюсь выше, был добавлен в .NET 4 Framework; так что вы можете использовать это, если вы находитесь в .NET 4. Смотрите пример здесь: http://weblogs.asp.net/gunnarpeipman/archive/2009/05/19/net-framework-4-0-using-system-lazy-lt-t-gt.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...