Я искал способы сделать ленивую инициализацию и нашел Lazy<T>
, который включен в .NET 4.
Я думал о том, чтобы выполнить собственную реализацию Lazy<T>
для .NET 3.5 (с более простой политикой с несколькими потоками), и я столкнулся с следующей проблемой:
Lazy имеет в основном два типа конструкторов:
class Lazy<T> {
public Lazy(){...} // ctor #1
который использует конструктор по умолчанию T для создания экземпляра T и
public Lazy(Func<T> func){...} // ctor #2
который позволяет вызывающему пользователю решить, как создается экземпляр T.
Теперь вот проблема:
Если мне нужна проверка времени компиляции для первого ctor, я добавлю ограничение
class Lazy<T> where T: new() {...}
на уровне класса. Это позволит мне использовать new T()
для создания экземпляра; но это ограничение не требуется для второго ctor, и, что еще хуже, оно также ограничивает типы, которые я могу использовать (для тех, у кого есть значение по умолчанию ctor)
Если я хочу использовать любой тип со вторым ctor, я не буду устанавливать никаких ограничений, и в 1-м ctor будет использоваться отражение, чтобы убедиться, что T
имеет значение по умолчанию ctor. Однако этот подход не будет проверять время компиляции и будет генерировать исключение только во время выполнения, если первый ctor используется с неправильным типом.
Мой вопрос: могу ли я получить лучшее из обоих миров?
В идеале я хотел бы получить проверку времени компиляции для каждого использования ctor # 1, но в то же время иметь возможность использовать ctor # 2 для типов, у которых нет значения по умолчанию ctor.
Как это делает реализация Microsoft? (У меня нет доступа к источникам или библиотекам .NET 4).
EDIT: (После "Reflector-ing" сборки MS)
Я проверил эталонную реализацию и не выполняет проверки времени компиляции.
Он использует отражение для случая "по умолчанию ctor", конечно, сопровождается исключением во время выполнения, если все идет плохо.