2013-09-28 7 views
2

비동기 메서드 내에서 SearchAysnc를 호출하는 Windows Phone 8의 연락처 개체로 작업하고 있습니다. SearchAsync를 사용하려면 처리기가 SearchCompleted 이벤트에 가입해야하며 async 메서드가 작업을 수행하는 데 필요한 이벤트 arg (다른 async 메서드 호출 포함) 중 하나를 통해 결과를 전달해야합니다.비동기 메서드 대기 이벤트 처리기에 의해 완료 신호가 있습니다.

이벤트의 비동기 완료, 즉 이벤트 패턴과 비동기/대기 패턴 간의 연결을 어떻게 기다리고 있습니까?

using System.Threading; 


async Task<string> MyMethod() 
{ 
    string result = null; 
    Contacts cons = new Contacts(); 
    EventWaitHandle handle = new EventWaitHandle(false,EventResetMode.ManualReset); 
    cons.SearchCompleted += (sender,args) => 
    { 
     // I do all my work on the results of the contact search in this handler 
     result = SomeOtherSynchronousOperation(args.Results); 

     // When I'm done, I release the thread which was waiting for the results 
     handle.Set(); 
    }; 
    cons.SearchAsync(String.Empty, FilterKind.None, "My Contact"); 

    // I can't block this thread (or can I?) 
    // So, I launch a task whose sole job is to wait 
    await Task.Run(()=> 
    { 
     // This gets released by the Contacts.SearchCompleted handler when its work is finished, 
     // so that MyMethod can finish up and deliver its result 
     handle.WaitOne(); 
    } 

    await DoOtherStuffWithResult(result); 

    return result; 
} 

내 실제 솔루션 (정확히 위 그림과 같이) 수행 작업 :

내가 가지고 올 수있는 유일한 솔루션

이 같은 기다려온 작업 일 이내에 기다리고, EventWaitHandle을 사용하는 것이 었습니다. 위의 코드가 구현 된 솔루션을 정확하게 표현하지는 않지만 (컴파일 문제 또는 두 가지 가능성이 있음) 개념을 표현하고 내 질문의 요점을 설명하는 역할을합니다.

이것이 유일한 방법인지 또는 이벤트 처리기의 실행을 기다리는 최적의 방법에 가까운 곳인지 궁금합니다. 그렇지 않은 경우 여기에 필요한 것을 수행하는 "최상의 방법"이 무엇인지 궁금합니다. .

Windows 동기화 프리미티브는 여전히 비동기/대기 세계에 위치합니까?

(제공된 답변에 따라)

이 정보가 맞습니까?

using Microsoft.Phone.UserData; 

string ExtractWhatIWantFromResults(IEnumerable<Contact> results) 
{ 
    string result; 

    // Do my processing on the list of contacts, stuff the results into result 

    return string; 
} 

async Task<string> MyMethod() 
{ 
    Contacts cons = new Contacts(); 
    TaskCompletionSource<string> tcs = new TaskCompletionSource<string>(); 

    cons.SearchCompleted += (sender,args) => 
    { 
     tcs.TrySetResult(ExtractWhatIWantFromResults(args.Results)); 
    }; 
    cons.SearchAsync(String.Empty, FilterKind.None, "My Contact"); 

    return tcs.Task; 
} 

답변

3

같은, 당신이 use TaskCompletionSource을해야, EAP 및 TAP를 해소하려면

public static Task<IEnumerable<Contact>> SearchTaskAsync(this Contacts contacts, string filter, FilterKind filterKind) 
{ 
    var tcs = new TaskCompletionSource<IEnumerable<Contact>>(); 
    EventHandler<ContactsSearchEventArgs> subscription = null; 
    subscription = (_, e) => 
    { 
    contacts.SearchCompleted -= subscription; 
    tcs.TrySetResult(e.Results); 
    }; 
    contacts.SearchCompleted += subscription; 
    contacts.SearchAsync(filter, filterKind, null); 
    return tcs.Task; 
} 

이처럼 사용할 수있는 :

async Task<string> MyMethodAsync() 
{ 
    Contacts cons = new Contacts(); 
    var searchResults = await cons.SearchTaskAsync(String.Empty, FilterKind.None); 
    string result = SomeOtherSynchronousOperation(searchResults); 
    await DoOtherStuffWithResult(result); 
    return result; 
} 

는 사실, MSDN docs for TAP이의 정말 비정상적으로 높은 품질과 전체 섹션을 통해 독서하는 것이 좋습니다.

Windows 동기화 프리미티브는 여전히 비동기식/대기중인 세계에 위치합니까?

스레드를 차단하자마자 비동기 코드의 이점을 상실하기 때문에 그리 중요하지 않습니다. 즉, TAP 기반의 프리미티브를 사용하여 유사한 동작을 에뮬레이션 할 수 있습니다. Stephen Toub has a series of blog entries 이걸 탐색하고 내 AsyncEx library에 비슷한 프리미티브를 구현했습니다.

5

TaskCompletionSource은 일반적인 방법입니다.

Task<string> MyMethodAsync() 
{ 
    Contacts cons = new Contacts(); 
    TaskCompletionSource<string> tcs = new TaskCompletionSource<string>(); 

    cons.SearchCompleted += (sender,args) => 
    { 
     tcs.TrySetResult(args.Results); 
    }; 
    cons.SearchAsync(String.Empty, FilterKind.None, "My Contact"); 

    return tcs.Task; 
} 
+1

내 편집 질문을 참조, (방법 클래스/메소드를 모른 채 테스트하는 어떤 생각을) 테스트되지 않음 ... 내가 이해 생각 ... 감사합니다! – Zenilogix

+0

@ L.B 비동기 한정자는이 메서드에서 필요하지 않습니다.이 메서드는 USES가 기다릴 때만 필요합니다 (이 메서드는 사용하지 않습니다). 또한 작업 을 "비동기"(예 : MyMethodAsync)로 반환하는 메서드의 이름을 지정하는 것이 좋습니다. – Ricibob

+0

@Ricibob 예, 그에 따라 답변을 업데이트했습니다. –