Это больше похоже на механизм кэширования, чем на "ленивую оценку". Кроме того, не изменяйте значение ссылки блокировки в блоке lock
. Используйте временную переменную для блокировки.
Ожидание, которое у вас есть сейчас, сработало бы в большом количестве случаев, но если бы у вас было два разных потока, попробуйте вычислить выражение в следующем порядке:
Thread 1
Thread 2
Thread 1 completes
Поток 2 никогда не завершится, потому что Поток 1 будет освобождать блокировку для другой ссылки, чем использовалась для получения блокировки (точнее, он будет освобождать несуществующую блокировку, поскольку вновь созданная ссылка никогда не блокировалась для начала), а не освобождает исходную блокировку, которая блокирует поток 2.
Хотя я не совсем уверен, что это будет делать (кроме выполнения синхронизированной оценки выражения и кэширования результата), это должно сделать его более безопасным:
public sealed class Lazy<T>
{
Func<T> getValue;
T value;
object lockValue = new object();
public Lazy(Func<T> f)
{
getValue = () =>
{
lock (lockValue)
{
value = f();
getValue = () => value;
}
return value;
};
}
public T Force()
{
return getValue();
}
}