almacenamiento en caché del resultado de un método de fábrica [n async] si no arroja

ACTUALIZACIÓN: Muy revisado después de que @usr señaló que había asumido incorrectamenteLazy<T>El modo de seguridad de hilo predeterminado eraLazyThreadSafetyMode.PublicationOnly...

Quiero calcular perezosamente un valor a través de unasync&nbsp;Método de fábrica (es decir, devuelveTask<T>) y guardarlo en caché en caso de éxito. A excepción, quiero que esté disponible para mí. Sin embargo, no quiero ser presa deel comportamiento de almacenamiento en caché de excepción&nbsp;eseLazy<T>&nbsp;tiene en su modo predeterminado (LazyThreadSafetyMode.ExecutionAndPublication)

Almacenamiento en caché de excepciones: cuando utiliza métodos de fábrica, las excepciones se almacenan en caché. Es decir, si el método de fábrica arroja una excepción la primera vez que un subproceso intenta acceder a la propiedad Value del objeto Lazy, se produce la misma excepción en cada intento posterior. Esto garantiza que cada llamada a la propiedad Value produzca el mismo resultado y evita errores sutiles que podrían surgir si diferentes hilos obtienen resultados diferentes. The Lazy representa una T real que, de lo contrario, se habría inicializado en algún momento anterior, generalmente durante el inicio. Una falla en ese punto anterior suele ser fatal. Si existe la posibilidad de una falla recuperable, le recomendamos que incorpore la lógica de reintento en la rutina de inicialización (en este caso, el método de fábrica), tal como lo haría si no estuviera utilizando la inicialización diferida.

Stephen Toub tiene unAsyncLazy&nbsp;clase y redacción&nbsp;eso parece correcto:

public class AsyncLazy<T> : Lazy<Task<T>>
{
    public AsyncLazy(Func<Task<T>> taskFactory) :
        base(() => Task.Factory.StartNew(() => taskFactory()).Unwrap())
    { }

    public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
}

sin embargo, ese es efectivamente el mismo comportamiento que el predeterminadoLazy<T>&nbsp;- Si hay un problema, no habrá reintentos.

Estoy buscandoTask<T>&nbsp;equivalente compatible deLazy<T>(Func<T>, LazyThreadSafetyMode.PublicationOnly), es decir, debe comportarse como se especifica:

Alternativa al bloqueo En ciertas situaciones, es posible que desee evitar la sobrecarga del comportamiento de bloqueo predeterminado del objeto Lazy. En situaciones raras, puede haber un punto muerto. En tales casos, puede usar el constructor Lazy (LazyThreadSafetyMode) o Lazy (Func, LazyThreadSafetyMode) y especificar LazyThreadSafetyMode.PublicationOnly. Esto permite que el objeto Lazy cree una copia del objeto vagamente inicializado en cada uno de varios hilos si los hilos llaman a la propiedad Value simultáneamente. El objeto Lazy garantiza que todos los subprocesos usen la misma instancia del objeto inicializado perezosamente y descarta las instancias que no se utilizan. Por lo tanto, el costo de reducir la sobrecarga de bloqueo es que su programa a veces puede crear y descartar copias adicionales de un objeto costoso. En la mayoría de los casos, esto es poco probable. Los ejemplos para los constructores Lazy (LazyThreadSafetyMode) y Lazy (Func, LazyThreadSafetyMode) demuestran este comportamiento.

IMPORTANTE

Cuando especifica PublicationOnly, las excepciones nunca se almacenan en caché, incluso si especifica un método de fábrica.

¿Hay alguna FCL,Nito.AsyncEx&nbsp;o una construcción similar que podría encajar bien aquí? De lo contrario, ¿puede alguien ver una manera elegante de bloquear el bit de "intento en progreso" (estoy de acuerdo con que cada persona que llama haga su propio intento de la misma manera que unLazy<T>(&nbsp;...(LazyThreadSafetyMode.PublicationOnly)&nbsp;lo hace) y aún así tener eso y la gestión de caché encapsulado perfectamente?