Zaman uyumsuz bir eylem temsilcisi yöntemini nasıl uygularsınız?


133

Biraz arka plan bilgisi.

Web API yığınını öğreniyorum ve tüm verileri Başarı ve Hata Kodları gibi parametrelerle bir "Sonuç" nesnesi biçiminde kapsüllemeye çalışıyorum.

Bununla birlikte, farklı yöntemler, farklı sonuçlar ve hata kodları üretir, ancak sonuç nesnesi genellikle aynı şekilde somutlaştırılır.

Biraz zaman kazanmak ve ayrıca C # 'da eşzamansız / bekleme yetenekleri hakkında daha fazla bilgi edinmek için, web api eylemlerimin tüm yöntem gövdelerini eşzamansız bir eylem temsilcisine sarmaya çalışıyorum, ancak biraz engelle karşılaştım ...

Aşağıdaki sınıflar göz önüne alındığında:

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 nesnesi üzerinde bir eylem gerçekleştiren ve onu döndüren bir yöntem yazmak istiyorum. Normalde eşzamanlı yöntemlerle bu,

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

Ama bu yöntemi async / await kullanarak asenkron bir yönteme nasıl dönüştürebilirim?

Bu denediğim şey:

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
newYukarıya çıkıyorsanız T, yönteminizin neden asenkron olması gerekiyor? Eşzamansız API'leri kullanan kodda AFAIK , yalnızca asynckullandığınız diğer yöntemlerden olanı yaymanız gerekir .
millimoose

Üzgünüm, bu konuda hala oldukça yeniyim, sadece yaymanız gerektiğini söylediğinizde ne demek istiyorsunuz ve T'nin bununla ne ilgisi var?
Albin Anke

Sanırım anladım, bana düşünmem için bir şey verdiğin için teşekkürler.
Albin Anke

1
Neden bunu eşzamansız yapmaya çalışıyorsun? Daha sık olarak, web sunucusu durumlarında, görevlere eşzamanlı kod sararak sahte eşzamansız yapmak (yapmaya çalıştığınız gibi), eşzamanlı yapmaktan daha yavaştır .
Scott Chamberlain

1
@AlbinAnke "propagate" ile demek istediğim, eğer bir yöntemdeki gibi bir .NET yöntemini çağırıyorsanız Stream.ReadAsync(), bu yöntemin kendisi zaman uyumsuz olmalı ve yöntem eşzamanlı olduğunda döndürdüğünüz bir Task<T>yere dönmelidir T. Buradaki fikir, bu şekilde, yönteminizi arayan her kişinin, temelin tamamlanması için "eşzamansız olarak" (bunun için iyi bir terim olduğunu bilmiyorum) beklemesidir Stream.ReadAsync(). Bunun için kullanabileceğiniz bir metafor, zaman uyumsuzluğun "bulaşıcı" olması ve düşük seviyeli yerleşik G / Ç'den sonuçları söz konusu G / Ç'ninkilere bağlı olan diğer koda yayılmasıdır.
millimoose

Yanıtlar:


307

asyncEşdeğer Action<T>olduğu Func<T, Task>bu aradığınız şey olduğuna inanıyoruz, bu yüzden:

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

@Stephen Açıkçası benzer bir MVVM ligth Messenger'a bazı benzerleri uygulamaya çalışıyorum, aynı şekilde uygulayabilir miyim?
Juan Pablo Gomez

@JuanPabloGomez: Onların mesajlaşma türlerine aşina değilim, ama neden işe yaramayacağını anlamıyorum.
Stephen Cleary

1
Bu harika! Eşzamansız bir Eylem yapmanın mümkün olmayacağını düşündüm ve bunu bir dil kusuru olarak görmüştüm. Bir Func kullanmayı düşünmedim. Teşekkürler.
Noel Widmer

2
@DFSFOT: Bir voidyöntemin eşzamansız eşdeğeri -returning Taskyöntemidir; Bu şekilde, bir zaman uyumsuz eş ActionIS Func<Task>ve zaman uyumsuz eş Action<T>olan Func<T, Task>. Daha fazla bilgi burada .
Stephen Cleary

1
@DFSFOT: Eşzamansız bir yöntem, Taskdönüş değeri olmadığında dönmelidir. asyncAnahtar kelimeyi kullanırsa, gerçek Taskörnek doğrudan işlev tarafından değil bir durum makinesi tarafından oluşturulacaktır.
Stephen Cleary

-11

Bu yüzden bunu uygulamanın yolunun şuna inanıyorum:

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
ASP.NET üzerinde kaçınmalısınız Task.Run(ve hatta daha fazlasını StartNew).
Stephen Cleary

Bunu yapmanın daha iyi bir yolu nedir?
Albin Anke

Bir cevap gönderdim ve @ svick'in cevabını da yükselttim. İkisi de iyi cevaplar.
Stephen Cleary
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.