간단한 wpf 데스크톱 응용 프로그램을 만들고 있습니다. UI에는 .cs 파일에있는 버튼과 코드 만 있습니다.
private void Button_Click_2(object sender, RoutedEventArgs e)
{
FunctionA();
}
public void FunctionA()
{
Task.Delay(5000).Start();
MessageBox.Show("Waiting Complete");
}
그러나 놀랍게도 라인 Task.Delay(5000).Start();
은 다음을 던지고 있습니다 InvalidOperationException
.
약속 스타일 작업에서는 시작을 호출 할 수 없습니다.
아무도 왜 이런 일을 도울 수 있습니까?
답변
Task
클래스가 작업을 제공하기 전에 이미 시작 했기 때문에 해당 오류가 발생 합니다. Start
생성자를 호출하여 생성 한 작업에 대해서만 호출해야하며 , 생성 할 때 작업을 시작하지 않을 설득력있는 이유가없는 한 그렇게해서는 안됩니다. 즉시 시작하려면을 사용 Task.Run
하거나 Task.Factory.StartNew
새로 만들고 시작 해야합니다 Task
.
그래서, 이제 우리는 그 성가신 Start
. 코드를 실행하면 메시지 상자가 5 초 후가 아니라 바로 표시된다는 것을 알게 될 것입니다. 그게 무슨 일입니까?
음, Task.Delay
5 초 안에 완료 될 작업을 제공합니다. 5 초 동안 스레드 실행을 중지하지 않습니다. 원하는 것은 해당 작업이 완료된 후 실행되는 코드가있는 것입니다. 그게 ContinueWith
목적입니다. 주어진 작업이 완료된 후 일부 코드를 실행할 수 있습니다.
public void FunctionA()
{
Task.Delay(5000)
.ContinueWith(t =>
{
MessageBox.Show("Waiting Complete");
});
}
예상대로 작동합니다.
C # 5.0의 await
키워드를 활용 하여 더 쉽게 연속을 추가 할 수도 있습니다.
public async Task FunctionA()
{
await Task.Delay(5000);
MessageBox.Show("Waiting Complete");
}
여기서 무슨 일이 벌어지고 있는지에 대한 전체 설명은이 질문의 범위를 벗어나지 만 최종 결과는 이전 방법과 매우 유사하게 작동하는 방법입니다. 메서드를 호출하면 5 초 후에 메시지 상자가 표시되지만 두 경우 모두 메서드 자체가 [거의] 즉시 반환됩니다. 즉, await
매우 강력하고 간단하고 직관적 인 메서드를 작성할 수 있지만 ContinueWith
직접 사용하여 작성하는 것이 훨씬 더 어렵고 지저분합니다 . 또한 많은 상용구 코드를 제거하여 오류 처리 처리를 크게 단순화합니다.
답변
이 시도.
private void Button_Click_2(object sender, RoutedEventArgs e)
{
FunctionA();
}
public async void FunctionA()
{
await Task.Delay(5000);
MessageBox.Show("Waiting Complete");
}
답변
Servy가 말했듯이 작업이 이미 시작되었으므로 남은 작업은 기다리는 것뿐입니다 (.Wait ()) :
private void Button_Click_2(object sender, RoutedEventArgs e)
{
FunctionA();
}
public void FunctionA()
{
Task.Delay(5000).Wait();
MessageBox.Show("Waiting Complete");
}