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


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.