У меня есть объект с недвижимостью, которая является дорогой для вычислений, таким образом, они только вычисляются на первый доступ и затем кэшируются.
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
или 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);
Если 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; }
}
Да , это возможно. Вопрос в том, сколько вы выиграете, сделав это - вам все равно где-то понадобится код инициализации, поэтому вы, в лучшем случае, сохраните условное выражение.
Некоторое время назад я реализовал класс, чтобы справиться с этим. Вы можете найти код, опубликованный в этом вопросе , где я спрашиваю, хорошая ли это идея. В ответах есть несколько интересных мнений, обязательно прочтите их все, прежде чем решиться на его использование.
В .NET 4 Framework был добавлен Lazy
Проблема с ??
заключается в том, что if CalcNotes ()
возвращает null
, тогда он больше не будет кэшироваться. То же самое для типов значений, если, например, в качестве значения свойства разрешены как 0
, так и NaN
.
Намного лучше было бы «аспектно-ориентированное» решение, что-то вроде Сообщение - Sharp использует атрибуты, а затем изменяет MSIL (байт-код).
Код будет выглядеть так:
[Cached]
public List<Note> Notes { get { return CalcNotes(); } }
РЕДАКТИРОВАТЬ: CciSharp.LazyProperty.dll делает именно это !!!