비동기 액션 대리자 메서드를 어떻게 구현합니까?


132

작은 배경 정보.

웹 API 스택을 배우고 있으며 Success 및 ErrorCodes와 같은 매개 변수를 사용하여 모든 결과를 "Result"개체 형식으로 캡슐화하려고합니다.

그러나 다른 방법은 다른 결과와 오류 코드를 생성하지만 결과 개체는 일반적으로 동일한 방식으로 인스턴스화됩니다.

시간을 절약하고 C #의 비동기 / 대기 기능에 대해 자세히 알아 보려면 웹 API 작업의 모든 메서드 본문을 비동기 작업 대리자로 래핑하려고하지만 약간의 걸림에 빠졌습니다.

다음과 같은 클래스가 주어집니다.

public class Result
{
    public bool Success { get; set; }
    public List<int> ErrorCodes{ get; set; }
}

public async Task<Result> GetResultAsync()
{
    return await DoSomethingAsync<Result>(result =>
    {
        // Do something here
        result.Success = true;

        if (SomethingIsTrue)
        {
            result.ErrorCodes.Add(404);
            result.Success = false;
        }
    }
}

Result 객체에서 작업을 수행하고 반환하는 메서드를 작성하고 싶습니다. 일반적으로 동기식 방법을 통해

public T DoSomethingAsync<T>(Action<T> resultBody) where T : Result, new()
{
    T result = new T();
    resultBody(result);
    return result;
}

그러나 async / await를 사용 하여이 메소드를 비동기 메소드로 어떻게 변환합니까?

이것이 내가 시도한 것입니다.

public async Task<T> DoSomethingAsync<T>(Action<T, Task> resultBody) 
    where T: Result, new()
{
    // But I don't know what do do from here.
    // What do I await?
}

1
new호출하는 경우 T왜 메소드가 비동기식이어야합니까? 비동기 API를 사용 하는 코드의 AFAIK에서는 사용async 하는 다른 방법에서 그 기능 을 전파하기 만하면됩니다.
밀리 모오스

죄송하지만 저는 아직 이것에 익숙하지 않습니다. 전파 만하면된다는 말의 의미는 무엇이며 T와의 새로운 관계는 무엇과 관련이 있습니까?
Albin Anke

나는 당신이 나에게 생각할 무언가를 줘서 고마워요.
Albin Anke

1
이 비동기 작업을 왜 시도하고 있습니까? 웹 서버가 아닌 상황에서 작업을 수행하는 것처럼 동기 코드를 랩핑하여 가짜 비동기 작업을 수행 하는 것은 동기식 작업보다 속도느립니다 .
Scott Chamberlain

1
@AlbinAnke "propagate" 는 메소드에서와 같이 .NET 메소드를 호출하는 경우Stream.ReadAsync() 해당 메소드 자체는 비동기식이어야하며 리턴 한 Task<T>위치 T는 메소드 동기식 이어야합니다 . 아이디어는 이렇게하면 메소드의 모든 호출자가 기본 Stream.ReadAsync()을 완료하기 위해 "비동기 적으로 기다릴 수 있습니다"(이것에 대한 좋은 용어는 무엇인지 알 수 없음)입니다 . 이것에 대한 은유는 비동기가 "감염성"이며 저수준 내장 I / O에서 결과가 상기 I / O의 결과에 의존하는 다른 코드로 확산된다는 것입니다.
millimoose

답변:


307

async의 상당 Action<T>하다 Func<T, Task>나는 이것이 당신이 찾고있는 무엇을 믿고, 그래서 :

public async Task<T> DoSomethingAsync<T>(Func<T, Task> resultBody)
    where T : Result, new()
{
  T result = new T();
  await resultBody(result);
  return result;
}

@Stephen 분명히 MVVM ligth Messenger에 비슷한 것을 구현하려고하는데 같은 방법으로 구현할 수 있습니까?
Juan Pablo Gomez

@ JuanPabloGomez : 나는 그들의 종류의 메시징에 익숙하지 않지만 왜 작동하지 않는지 알 수 없습니다.
Stephen Cleary

1
이것은 놀랍다! 비동기 작업을 수행 할 수 없다고 생각하고 이미 언어 결함으로 간주했습니다. Func 사용에 대해서는 생각하지 않았습니다. 감사.
Noel Widmer

2
@DFSFOT : void메소드 의 비동기 항목 은 Task-returning 메소드입니다. 따라서, 비동기의 등가 ActionIS Func<Task>와의 비동기 당량 Action<T>이다 Func<T, Task>. 자세한 내용은 여기를 참조하십시오 .
Stephen Cleary

1
@DFSFOT : Task반환 값이없는 비동기 메서드가 반환되어야 합니다. async키워드를 사용하는 경우 실제 Task인스턴스는 함수가 아닌 상태 머신에 의해 작성됩니다.
Stephen Cleary 2014

-11

그래서 이것을 구현하는 방법은 다음과 같습니다.

public Task<T> DoSomethingAsync<T>(Action<T> resultBody) where T : Result, new()
{
    return Task<T>.Factory.StartNew(() =>
    {
        T result = new T();
        resultBody(result);
        return result;
    });
}

7
당신은 피해야한다 Task.Run(그리고 더욱 더 StartNewASP.NET에).
Stephen Cleary

더 좋은 방법은 무엇입니까?
Albin Anke

나는 답변을 게시하고 @svick의 답변도 올렸습니다. 둘 다 좋은 대답입니다.
Stephen Cleary
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.