Кэшируемое Свойство: Более легкий путь?

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

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

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

37
задан John Saunders 11 July 2010 в 20:54
поделиться

6 ответов

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

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

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

23
ответ дан 27 November 2019 в 04:48
поделиться

На мой взгляд, это довольно стандартно. То, что ты делаешь, нормально.

5
ответ дан 27 November 2019 в 04:48
поделиться

В .NET 3.5 или более ранней версии у вас есть очень стандартная практика и прекрасная модель. .

(Хотя я бы посоветовал вернуть IList или IEnumerable , если возможно, вместо List в вашем общедоступном API - List должен быть деталью реализации ...)

Однако в .NET 4 есть более простой вариант: Lazy . Это позволяет вам сделать:

private Lazy<IList<Note>> notes;
public IEnumerable<Note> Notes
{
    get
    {
        return this.notes.Value;
    }
}

// In constructor:
this.notes = new Lazy<IList<Note>>(this.CalcNotes);
21
ответ дан 27 November 2019 в 04:48
поделиться

Если value вычислить нетривиально, я обычно предпочитаю использовать метод ( 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
ответ дан 27 November 2019 в 04:48
поделиться

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

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

Правка:

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

1
ответ дан 27 November 2019 в 04:48
поделиться

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

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

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

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

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

6
ответ дан 27 November 2019 в 04:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: