2013-01-25 2 views
1

저는 다른 개발자가 사용하기 위해 RESTful 웹 서비스를 래핑하는 클래스 라이브러리를 개발 중입니다. System.Net.Http 네임 스페이스의 HttpClient 유형을 사용하여 모든 API 호출을 비동기 적으로 수행합니다.비동기 메소드를 공개해야합니까?

단순히 콘텐츠를 보내고받는 것 외에도 반환 된 XML 데이터에 대해 추가 처리를 수행하려고합니다. 아무리 당신이 그것을 넣어,이 클래스 라이브러리의 어딘가에 Async/Await 키워드를 사용하여 포함됩니다.

제 질문은 Async 키워드를 사용하는 메소드를 노출하는 것이 좋은지 나쁜지는 제 질문입니다. 어딘가에 비동기 메서드를 비공개로 설정 한 다음 return 문으로 추가 메서드를 만들어야한다고 읽었습니다. 그게 내가하고있는 일이지만, 그것이 옳다고 생각하지 않습니다.

Public Function InvokeAsync(command As HttpRequestMessage) As Task(Of CommandResult) 
    Return InvokeAsyncInternal(command) 
End Function 

Private Async Function InvokeAsyncInternal(command As HttpRequestMessage) As Task(Of CommandResult) 
    Dim rawCommandResult As HttpResponseMessage = Await myHttpClient.SendAsync(command) 
    Dim finalResult As CommandResult = AdditionalProcessing(rawCommandResult) 
    Return finalResult 
End Function 

이 아주 간략 코드 샘플임을 명심 : 거기에 어떤 좋은 인수를 직접 비동기 방법을 노출하지?

+0

"어딘가 읽었어요 ..."어디에서 읽었습니까? 링크가 있습니까? 일반적으로 누군가가 그렇게 말하면서 무언가를하면 안된다고 생각합니다. 그들의 논증이 의미가 있고 당신이 그것에 동의하기 때문에 그것을해야합니다. – svick

+0

그것은 인터넷상의 어딘가에있는 많은 "비동기/소개 대기"블로그 게시물 중 하나였습니다. 그 당시에는 의미가 있었지만 지금은 가치를 추가하지 않는 것으로 보아 다시 생각하기 시작했습니다. –

답변

3

이것은 컴파일러 변환과 관련이 있습니다. "실제"Async 메서드를 해당 Public 메서드에서 분리 할 수 ​​있으며 이터레이터 (Yield) 메서드에서 같은 종류의 분리 작업을 수행 할 때와 같은 이점을 얻을 수 있습니다.

특히, 예외는 Async 메서드에서 throw 될 때와 비교하여 래퍼에서 throw 될 때 다르게 처리됩니다. Async 메서드가 Task을 반환하면 Exception이 반환되고 호출자에게 직접 throw되지 않고 반환 된 Task에 배치됩니다. Public 래퍼 메서드 (Async이 아님)가 Exception을 throw하면 호출자에게 직접 throw됩니다.

그러므로 사전 조건 스타일 검사는 Public 메서드에 입력 할 수 있습니다. 호출자는 Task에있는 예외를 무시할 수 있지만 직접 throw 된 예외는 무시할 수 없습니다. 전제 조건 예외를 Public 래퍼에 배치하면 호출자가 API를 잘못 사용하고 있음을 알게되고 런타임 예외 (즉, Task에 위치)에서 사용 예외 (즉 직접 throw 된)를 분리 할 수 ​​있습니다.

메소드에 전제 조건이없는 경우 Public 래퍼가 내측 Task을 반환합니다. 이 경우 Public 랩퍼는 필요하지 않습니다. 예외가 전에 첫 번째 AWAIT을 을 던져하지만, 예외가 유일한 작업을 검사에 슬로우 다시 것을

void Caller() 
{ 
    var t = AsyncThatThrows(null); 
    // ... 
    Task.WaitAny(t, t2); // <-- exception thrown here 
} 

Task AsyncThatThrows(Object o) 
{ 
    if (o == null) 
     throw new ArgumentNullException("o"); 

    // ... 
    await // ... 
    // ... 
} 

참고 :

+0

그래서'Async' 또는'Iterator' 키워드로 메서드를 노출시키지 않도록 내 메서드를 래핑하는 것은 완전히 무의미한가요? 유효하지 않은 입력은 웹 서비스에서 올바르게 처리되므로 유효성 검사에 대해 걱정할 필요가 없습니다. –

+0

무의미하지 않고 때로는 필요합니다. 예를 들어, 응용 프로그램의 첫 번째 부분에서 예외를 throw하면 함수를 기다리지 않으면 자연스럽게 예외가 발생하지 않습니다. –

+0

@ ToniPetrina하지만 메서드를 래핑하는 것은 아무 것도하지 않습니다. 예외가 표현되는 방식에는 영향을주지 않습니다. – svick

0

다음과 같은 시나리오를 생각해보십시오. 그것을 기다리 느냐, 결과를 얻 느냐. 다음과 같은 방법으로 그것을 구현하기로 선택한 경우 :

void Caller() 
{ 
    var t = AsyncThatThrows(null);// <-- exception thrown here 
    // ... 
    Task.WaitAny(t, t2); 
} 

Task AsyncThatThrows(Object o) 
{ 
    if (o == null) 
     throw new ArgumentNullException("o"); 

    return AsyncThatThrows_Impl(o); 
} 

Task AsyncThatThrows_Impl(Object o) 
{ 
    // ... 
    await // ... 
    // ... 
} 

는 이제 예외가 호출
를 잡을 수, 당신은 작업을 검사 할 필요가 없습니다. 전자의 경우 비동기 파트를 아직 시작하지 않았지만 예외는 결과로 생성 된 Task에 저장됩니다.

+0

이 내용은 컴파일러가 무엇을하는지 전혀 모르는 사람에게 이해하기가 어렵습니다. –

관련 문제