armazenando em cache o resultado de um método de fábrica [n assíncrono] se ele não gerar

ATUALIZAÇÃO: Fortemente revisada após @usr apontar que eu assumi incorretamenteLazy<T>O modo de segurança de linha padrão doLazyThreadSafetyMode.PublicationOnly...

Quero calcular preguiçosamente um valor por meio de umasync Método de fábrica (ou seja, retornaTask<T>) e armazená-lo em cache após o sucesso. Com exceção, quero que isso esteja disponível para mim. No entanto, não quero ser vítima deo comportamento de cache de exceção esteLazy<T> tem em seu modo padrão (LazyThreadSafetyMode.ExecutionAndPublication)

Armazenamento em cache de exceção: quando você usa métodos de fábrica, as exceções são armazenadas em cache. Ou seja, se o método factory lança uma exceção na primeira vez que um thread tenta acessar a propriedade Value do objeto Lazy, a mesma exceção é lançada em todas as tentativas subseqüentes. Isso garante que todas as chamadas para a propriedade Value produzam o mesmo resultado e evitam erros sutis que podem surgir se threads diferentes obtiverem resultados diferentes. O Lazy representa um T real que, de outra forma, teria sido inicializado em algum momento anterior, geralmente durante a inicialização. Uma falha nesse ponto anterior é geralmente fatal. Se houver um potencial de falha recuperável, recomendamos que você crie a lógica de nova tentativa na rotina de inicialização (neste caso, o método de fábrica), como faria se não estivesse usando a inicialização lenta.

Stephen Toub tem umAsyncLazy classe e redação isso parece certo:

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(); }
}

no entanto, esse é efetivamente o mesmo comportamento padrãoLazy<T> - se houver algum problema, não haverá novas tentativas.

eu estou procurando umaTask<T> equivalente compatível deLazy<T>(Func<T>, LazyThreadSafetyMode.PublicationOnly), ou seja, deve se comportar conforme especificado: -

Alternativa ao bloqueio Em determinadas situações, convém evitar a sobrecarga do comportamento de bloqueio padrão do objeto Lazy. Em situações raras, pode haver um potencial de impasse. Nesses casos, você pode usar o construtor Lazy (LazyThreadSafetyMode) ou Lazy (Func, LazyThreadSafetyMode) e especificar LazyThreadSafetyMode.PublicationOnly. Isso permite que o objeto Lazy crie uma cópia do objeto inicializado lentamente em cada um dos vários threads, se os threads chamarem a propriedade Value simultaneamente. O objeto Lazy garante que todos os threads usem a mesma instância do objeto inicializado lentamente e descarte as instâncias que não são usadas. Portanto, o custo de reduzir a sobrecarga de bloqueio é que seu programa às vezes pode criar e descartar cópias extras de um objeto caro. Na maioria dos casos, isso é improvável. Os exemplos para os construtores Lazy (LazyThreadSafetyMode) e Lazy (Func, LazyThreadSafetyMode) demonstram esse comportamento.

IMPORTANTE

Quando você especifica PublicationOnly, as exceções nunca são armazenadas em cache, mesmo se você especificar um método de fábrica.

Existe alguma FCL,Nito.AsyncEx ou construção semelhante que possa se encaixar muito bem aqui? Se isso não acontecer, alguém pode ver uma maneira elegante de bloquear o bit "tentativa em andamento" (estou bem com cada chamador fazendo sua própria tentativa da mesma maneira que umLazy<T>( ...,(LazyThreadSafetyMode.PublicationOnly) ainda) e ainda o possui e o gerenciamento de cache é encapsulado ordenadamente?

questionAnswers(4)

yourAnswerToTheQuestion