.NET

индекс
121,03

Lazy<T>: конструирование объектов по требованию в .NET 4.0

Мне нравится, когда я нахожу новые части функциональности в .NET framework. Это все те большие интересности, которые получают всю любовь и признание на конференциях и в журналах.

Lazy<T> как раз один из таких.

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

Конечно, вы можете разобраться с этим самостоятельно, но Lazy<T> сделает это проще. Вы просто создаете ленивую обертку на дорогостоящем объекте:

Lazy<ExpensiveResource> ownedResource = new Lazy<ExpensiveResource>();

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

Lazy<T> также имеет булевое свойство, называющееся IsValueCreated, которое вы можете проверить чтобы увидеть был ли создан объект в свойстве Value. Это может оказаться полезным когда вам нужно хранить информацию из дорогостоящего ресурса, но только если она будет использована.

Поддержка типов без конструкторов по умолчанию


Lazy<T> не навязывает ограничение на наличие new(). Вы можете использовать Lazy<T> для типов, которые должны быть созданы с помощью других конструкторов и даже фабричных методов. Второй конструктор определяет делегат Func<T> который возвращает новый дорогостоящий ресурс:

Lazy<ExpensiveResource> ownedResource = new Lazy<ExpensiveResource>(
   () => new ExpensiveResource("filename.data"));


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

Мы живем в многоядерном мире


Lazy<T> имеет еще два конструктора:

public Lazy(bool isThreadSafe);
public Lazy(Func<T> valueFactory, bool isThreadSafe);


Эти два конструктора показывают что вы запускаете в мультипотоковом окружении, и ленивое создание объекта должно быть синхронизировано.(Помимо всего прочего, это дорогостоящий ресурс. Вам не нужно чтобы их было несколько.)

Это простой тип, но это один из тех типов которые, как вы будете находить полезным для себя снова и снова.

Я рад, что это было добавлено.

Tags: C#, .NET General, C# General, DevCenterPosts
+22
24 ноября 2009, 09:44
21

комментарии (31)

0
Oblitus #
Неплохая идея. Пошел писать аналог для java.
0
romaklimenko #
Без многопоточности там вообще простая реализация.
0
Oblitus #
Сложность будет с генериками, чтобы выглядело красиво. Список параметров для конструктора придется делать извращенным способом.
+3
acerv #
Чувствую себя вымирающим мамонтом. Я и 2.0 то не до конца еще заботал, а тут уже такое.
+2
SHSE #
Рискуете потерять конкурентоспособность. Рекомендую ежедневно заглядывать на dotnetkicks.com.
+1
acerv #
Спасибо, я лучше буду дальше в глухой бакэнд уходить:) MS SQL в этом плане не так сильно летит вперед.
+1
romaklimenko #
Это только кажется, пока не придется поработать с PowerShell, CLR процедурами и т.п. Синтаксисом второго сишарпа можно и в четвертом писать, а вот править то, что написали другие — не всегда.
0
acerv #
извините, я не совсем понял, что вы хотите сказать.
+1
hTLK #
Например целесообразно использовать в MS SQL хранимые процедуры, написанные на .NET'е.
Для некоторых задач будет работать и быстрее и проще.
0
acerv #
а CLR, разумеется, нужно писать на 4.0, с использованием Lazy? :)
+1
hTLK #
Не обязательно, но с этой точки зрения MS SQL летит вперёд настолько же быстро, как и сам .NET. Например технология LINQ to XML очень облегчает работу с XML из SQL Server'а, а в .NET 2.0 её нету.

Это как и везде — чем больше инструментарий, тем проще решать задачи.
0
acerv #
Вы путаете предметы разработки. Технология Linq-xml никакого отношения к базе данных MS SQL не имеет. С точки зрения программирования, MS SQL абсолютно обособленный объект. Однохренственно, кто для нее клиент, linq-to-xml, link-to-sql, datareader или еще кто-нибудь.
0
vktechno #
Все-таки работа с Sql Server не ограничивается написанием sql-кода.
0
acerv #
согласен с вами целиком и полностью.
0
imil #
Некогда точить пилу, надо пилить? :)
+2
acerv #
Нет, почему, пилу точу. Дело не в пиле, а в том, чтобы дать технологии время улежаться в голове, устаканиться. Летим ведь, непонятно куда.
0
AigizK #
в последнее время столько разных технологий у мелкософта появились даже для решений одних задач. что за всем физически не успеваешь.
+1
ETCDema #
Да уж… Мало применить технологию, нужно применить ее грамотно. Что бы применить грамотно нужно время для того, что бы попробовать, потестировать и найти оптимальный подход для использования (желательно на каком-нибудь некритичном проекте) плюс ко всему определить стратегию использования совместно с другими используемыми технологиями (или замены чего-либо).
А последнее время идет плотный поток технологий и их реализаций, на все физически не хватает рук и времени, да и постоянные смены технологий в проекте — зло.
Меня забавляют коллеги, которые прилетают и рассказывают с упоением о какой-то новой штучке, которые они непременно будут использовать вот прям сейчас и все, что они раньше использовали — устаревшее никому ненужное УГ (особенно смешно выглядел крайне увлеченный чувак, который рассказывал ген.директору о супер продвинутой технологии ZOPE… попробуйте послушать со стороны — это что-то).
0
romaklimenko #
Тем не менее, имхо, новым возможностям стоит радоваться, а не «сидеть в пещере с гоблинами» (с).

Я помню как я сам был недоволен странным синтаксисом LINQ и тем что они вообще городят непонятно что. Оказалось, достаточно понять несколько не таких уж сложных базовых концепций, чтобы этот самый LINQ был, как говорится, на кончиках пальцев. И мне сейчас его не хватает когда приходится работать с кодом на .NET 2.0

Другое дело, что зрелые зарекомендовавшие себя технологии не становятся хуже от появления новых технологий с новыми возможностями.
+1
ETCDema #
Так я и не предлагаю сидеть :) просто нужно поменьше фанатизма и побольше здравого смысла, а не кидаться на все подряд.
0
romaklimenko #
Ну тогда да, тут я полностью согласен )
+1
pcholberg #
Вспоминая синглтона Мейерса на C++:

static T& Instance()
{
static T instance;
return instance;
}


Насколько я понимаю сделали именно это)
+1
mraleph #
fyi: этот синглтон не thread-safe
0
CriggerMarg #
неплохо. Если еще обернуть все фабрикой — вообще красота будет
+1
Sane #
Похоже, второй конструктор как раз и принимает фабрику.
0
Ordos #
Думаю, ещё полезно было бы иметь аналогичную обёртку для WeekReference, чтобы объект ещё и сам освобождался при необходимости.
0
LostByte #
В .NET/С# я пожалуй могу считать себя любителем, но кое что кодил и кодю:) После прочтения поста сразу же возник вопросы:
1. Если я правильно понял — это лишь экономия нескольких строк кода?
2. Хотелось бы увидеть конкретные примеры, как это сделать без Lazy и с Lazy, почувствовать, увидеть и поосязать разницу:)

Lazy ведь просто «фишка», востребованность которой крайне невелика. А вот механизмы Reflection и LINQ можно пожалуй назвать в некотором роде инновационными, хотя вокруг них маловато движухи среди .NET программистов в интернете на мой взгляд.

.NET framework вообще очень интересно эволюционирует, мне наиболее интересно наблюдать за постепенным слиянием WPF/.NET3.5 и Silverlight:)
0
mezastel #
1. Да, но объем экономии зависит от того, нужна потокобезопасность или нет.
2. Мне тоже.
0
self #
Это экономия не кода, а ресурсов и/или процессорного времени, улучшает масштабируемость. Позволяет отложить выделение ресурса до момента, когда он реально будет запрошен (будет вызвано свойство Value). А за это время кто-то другой может успеть попользоваться ресурсом, даже если этот ресурс — процессорное время.

Насчет Reflection — это еще в первой версии .net появилось, 10 лет назад. Метаданные и средства доступа к ним это краеугольный камень всей технологии .net. А Linq просто еще не набрал массы юзеров, я вот например только сейчас за него сел, в связи с тотальным обновлением софта и тулзов (WinXP -> Win7, VS2005 -> 2008).
0
mezastel #
Откровенно говоря, меня беспокоит кол-во полезного материала в этом посте. Если уж и говорить про Lazy<T>, то нужно по крайней мере упомянуть альтернативные методы реализации, а также «раскрыть тему» потокобезопасности ленивого инициализатора.

Тот факт что этот пост – перевод, не снимает ответственности за весьма посредственный подход к теме.
0
romaklimenko #
Собственно, я не брал на себя никакой ответственности сделать подход к теме «непосредственным». Оригинальная статья оказалась для меня полезной и интересной, т.к. я узнал о том, что в .NET 4.0 будет такая полезная фишечка. Теперь нужно дождаться релиза.

Если в этой теме кого-то интересует многопоточность, отличие от других реализаций, то я рад, конечно, но это тема для отдельной статьи. Почитайте MSDN, здесь более подробно: msdn.microsoft.com/en-us/library/dd997286%28VS.100%29.aspx

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