Files
Umbraco-CMS/src/Umbraco.Core/Cache/SafeLazy.cs
2020-02-24 08:21:53 +01:00

64 lines
2.2 KiB
C#

using System;
using System.Runtime.ExceptionServices;
namespace Umbraco.Core.Cache
{
public static class SafeLazy
{
// an object that represent a value that has not been created yet
internal static readonly object ValueNotCreated = new object();
public static Lazy<object> GetSafeLazy(Func<object> getCacheItem)
{
// try to generate the value and if it fails,
// wrap in an ExceptionHolder - would be much simpler
// to just use lazy.IsValueFaulted alas that field is
// internal
return new Lazy<object>(() =>
{
try
{
return getCacheItem();
}
catch (Exception e)
{
return new ExceptionHolder(ExceptionDispatchInfo.Capture(e));
}
});
}
public static object GetSafeLazyValue(Lazy<object> lazy, bool onlyIfValueIsCreated = false)
{
// if onlyIfValueIsCreated, do not trigger value creation
// must return something, though, to differentiate from null values
if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated;
// if execution has thrown then lazy.IsValueCreated is false
// and lazy.IsValueFaulted is true (but internal) so we use our
// own exception holder (see Lazy<T> source code) to return null
if (lazy.Value is ExceptionHolder) return null;
// we have a value and execution has not thrown so returning
// here does not throw - unless we're re-entering, take care of it
try
{
return lazy.Value;
}
catch (InvalidOperationException e)
{
throw new InvalidOperationException("The method that computes a value for the cache has tried to read that value from the cache.", e);
}
}
public class ExceptionHolder
{
public ExceptionHolder(ExceptionDispatchInfo e)
{
Exception = e;
}
public ExceptionDispatchInfo Exception { get; }
}
}
}