Existe um método simples e agradável de atrasar uma chamada de função enquanto permite que o thread continue em execução?
por exemplo
public void foo()
{
// Do stuff!
// Delayed call to bar() after x number of ms
// Do more Stuff
}
public void bar()
{
// Only execute once foo has finished
}
Estou ciente de que isso pode ser feito usando um cronômetro e manipuladores de eventos, mas gostaria de saber se existe uma maneira c # padrão de fazer isso.
Se alguém estiver curioso, isso é necessário porque foo () e bar () estão em classes diferentes (singleton) que precisam ser chamadas em circunstâncias excepcionais. O problema é que isso é feito na inicialização, então foo precisa chamar bar, que precisa de uma instância da classe foo que está sendo criada ... daí a chamada atrasada para bar () para garantir que foo esteja totalmente instanciado .. Lendo isso de volta quase cheira a um design ruim!
EDITAR
Vou levar em consideração os pontos sobre design ruim! Há muito tempo pensei que poderia melhorar o sistema, entretanto, essa situação desagradável só ocorre quando uma exceção é lançada, em todas as outras vezes os dois singletons coexistem muito bem. Acho que não vou mexer com padrões assíncronos desagradáveis, em vez disso, vou refatorar a inicialização de uma das classes.
Awake
eStart
fases. NaAwake
fase, você se configura e, no final desta fase, todos os objetos são inicializados. Durante aStart
fase, os objetos podem começar a se comunicar uns com os outros.Respostas:
Graças ao C # 5/6 moderno :)
fonte
Eu mesmo tenho procurado algo parecido com isso - eu vim com o seguinte, embora use um cronômetro, ele usa apenas uma vez para o atraso inicial e não requer nenhuma
Sleep
chamada ...(obrigado a Fred Deschenes pela ideia de descartar o cronômetro dentro do callback)
fonte
timer
variável local de dentro do lambda que é vinculado ao objeto delegadocb
faz com que ele seja içado para um armazenamento anon (detalhe de implementação de fechamento) que fará com que oTimer
objeto seja alcançável da perspectiva do GC enquanto oTimerCallback
próprio delegado estiver acessível . Em outras palavras,Timer
é garantido que o objeto não será coletado como lixo até que o objeto delegado seja chamado pelo pool de threads.Além de concordar com as observações de design dos comentadores anteriores, nenhuma das soluções foi suficientemente limpa para mim. .Net 4 fornece
Dispatcher
eTask
classes que tornam bastante simples atrasar a execução no thread atual :Por contexto, estou usando isso para depurar um
ICommand
botão esquerdo do mouse vinculado a um elemento de interface do usuário. Os usuários clicam duas vezes, o que está causando todo tipo de confusão. (Sei que também poderia usarClick
/DoubleClick
handlers, mas queria uma solução que funcionasse comICommand
s em todos os níveis).fonte
Parece que o controle da criação de ambos os objetos e sua interdependência precisam ser controlados externamente, em vez de entre as próprias classes.
fonte
É realmente um design muito ruim, quanto mais um singleton por si só é um design ruim.
No entanto, se você realmente precisa atrasar a execução, eis o que você pode fazer:
No entanto, isso será invocado
bar()
em um thread separado. Se você precisar chamarbar()
o thread original, pode ser necessário mover abar()
invocação para oRunWorkerCompleted
manipulador ou fazer um pouco de hackingSynchronizationContext
.fonte
Bem, eu teria que concordar com o ponto de "design" ... mas você provavelmente pode usar um Monitor para avisar um quando o outro já passou da seção crítica ...
fonte
Uso:
fonte
Achei que a solução perfeita seria ter um cronômetro para lidar com a ação atrasada. O FxCop não gosta quando você tem um intervalo de menos de um segundo. Preciso atrasar minhas ações até DEPOIS que meu DataGrid concluiu a classificação por coluna. Achei que um temporizador de disparo único (AutoReset = false) seria a solução e funciona perfeitamente. E, FxCop não me deixa suprimir o aviso!
fonte
Isso funcionará em versões mais antigas do .NET
Cons: será executado em seu próprio thread
Uso:
fonte
Não existe uma maneira padrão de atrasar uma chamada para uma função, a não ser usando um cronômetro e eventos.
Isso soa como o anti-padrão da GUI de atrasar uma chamada para um método para que você possa ter certeza de que o layout do formulário foi concluído. Não é uma boa ideia.
fonte
Com base na resposta de David O'Donoghue, aqui está uma versão otimizada do Delayed Delegate:
A classe poderia ser melhorada um pouco mais usando uma chave exclusiva para os delegados. Porque se você adicionar o mesmo delegado uma segunda vez antes de disparar o primeiro, poderá ter um problema com o dicionário.
fonte
fonte