Отложенная (ленивая) инициализация
Ленивая инициализация объекта означает, что его создание откладывается до его первого использования. Она в основном используется для повышения производительности, предотвращения ненужных вычислений и снижения потребления памяти программой. Наиболее распространённые сценарии:
- Ресурсоёмкий объект, который программа может и не использовать. Например, объект
Customer со свойством Orders (массив заказов), для инициализации которого требуется запрос из базы данных. Если пользователю не нужны заказы, то нет причин тратить память или время на создание массива Orders. Используя Lazy<Orders>, чтобы объявить отложенную инициализацию объекта Orders, можно избежать расхода системных ресурсов на неиспользуемый объект.- Ресурсоёмкий объект, создание которого можно отложить. Например, программа загружает несколько экземпляров объекта при запуске, но только некоторые из них требуются немедленно. Можно ускорить запуск программы, отложив инициализацию ненужных объектов до тех пор, пока они не понадобятся.
Базовое использование
Lazy<Orders> orders = new Lazy<Orders>();В этом случае объект параметра типа создаётся при первом использовании (обращении к свойству
...
var listOfOrders = orders.Value; //использование
Value) с помощью Activator.CreateInstance, а сам тип Orders должен иметь конструктор без параметров. Кроме того, ленивому конструктору можно передать параметры:-
bool isThreadSafe – по умолчанию true, то есть создаётся потокобезопасный объект. Первый поток инициализирует объект, далее все потоки используют одни и те же данные. Если предполагается использование в единственном потоке, значение false позволяет получить небольшой выигрыш в быстродействии.-
Func<Orders> valueFactory - лямбда-выражение, позволяющее выполнить любые действия, необходимые для инициализации объекта (см. пример ниже).-
Orders value – предварительно инициализированное значение.После создания объекта
Lazy экземпляр Orders не создается до первого доступа к свойству Value переменной orders. Объект Lazy<T> всегда возвращает тот же объект или значение, которые использовались для его инициализации. Следовательно, свойство Value доступно только для чтения.Чтобы реализовать открытое свойство с помощью отложенной инициализации, определите вспомогательное поле свойства как
Lazy<T> и верните свойство Value из аксессора (get) свойства:class Customer {
private Lazy<Orders> orders;
public string CustomerID {get; private set;}
public Customer(string id) {
CustomerID = id;
orders = new Lazy<Orders>(() =>
{
// дополнительная логика инициализации
return new Orders(this.CustomerID);
});
}
public Orders MyOrders {
get {
return orders.Value;
}
}
}
Поскольку свойство Value доступно только для чтения, у свойства Orders нет мутатора (set). Изменить значение ленивого объекта нельзя, можно только инициализировать новый объект. Если требуется изменяемое ленивое свойство, мутатор должен:- создать новое лямбда-выражение, возвращающее переданное мутатору значение,
- передать выражение в конструктор нового объекта
Lazy<T>,- присвоить новый объект вспомогательному полю.
Тогда последующее обращение к аксессору (get) свойства приведёт к новой инициализации ленивого объекта и вернёт новое значение.
Источник: https://docs.microsoft.com/en-us/dotnet/framework/performance/lazy-initialization