2017-01-19 15 views
6

F # dan C# kütüphanesi tüketmek istiyorum. Çoğunlukla bu oldukça basit olmuştur. Ancak, bir Task<T> döndüren bir işlevi çağırmaya çalışırsanız, döndürülen değeri alamıyorum.F # türünde bir async C# yöntemiyle doğru bir şekilde bekletme Görev türü <T>

Yani, aşağıdaki tanımıyla C# yöntemi vardır:

public async Task<TEvent> ReadEventAsync<TEvent>(string streamName, int position) where TEvent: class 

Ve şöyle F # gelen bu yöntemi tüketmeye çalışıyorum:

let readEventFromEventStore<'a when 'a : not struct> (eventStore:IEventStoreRepository) (streamName:string) (position:int) = 
    async { 
      return eventStore.ReadEventAsync(streamName, position) 
      |> Async.AwaitTask 
      } 

Ben kısmen bu işlevi uygulamak Olayı almak istediğiniz bir IEventStoreRepository örneğini ve akış adını:

let readEvent = readEventFromEventStore eventStore streamName 
Ben event değerini aldığınızda

let event = readEvent StreamPosition.Start 

bir FSharpAsync<object> yerine beklediğimden Task<T> den T geçerli:

Sonra son olarak, kalan parametreyi geçerlidir.

Task<T> bir dönüş türü ile C# ile yazılmış bir async yöntemini çağırarak ve T değerini erişmenin F # doğru yöntem nedir?

+1

Geri dönüşü deneyin! eventStore. ... 'dönüş eventStore yerine. ... '? – ildjarn

+0

@ildjarn - Sadece orada denedim. Ne yazık ki, aynı sonucu yani FSharpAsync 'döndürür. –

cevap

9

Her şeyden önce, kullanım durumunuzda, async { } bloğuna gerek yoktur. Async.AwaitTask returns an Async<'T>, böylece async { } bloğunuz sadece aldığınız ve hemen yeniden sardığınız Async nesnesini kaldırıyor. Şimdi gereksiz async bloğun elden çıkartıldı ettik

, Diyelim ki ele verdik tip bakalım ve türü olsun istedi. Async<'a> aldınız ve 'a türünde bir nesne istiyorsunuz. available Async functions aracılığıyla, Async<'a> -> 'a gibi bir tür imzası olan, Async.RunSynchronously'dur. İki isteğe bağlı parametresi, bir int ve bir CancellationToken alır, ancak bunları çıkarırsanız, aradığınız işlev imzası vardır. Ve yeterince emin, bir kez dokümanlar bakmak o Async.RunSynchronously olduğunu C# 's await F # eşdeğeri, ne istediğinizdir. türünde bir sıralama (tam olarak değil) C# 'yı await. C# async işlevinin bir async işlevi içinde kullanabileceğiniz bir deyimdir, ancak async nesnesinin async nesnesi, async nesnesinin çalışmasını bitirinceye kadar geçerli iş parçacığını engeller. Tam da bu durumda aradığın şey tam olarak bu.

let readEventFromEventStore<'a when 'a : not struct> (eventStore:IEventStoreRepository) (streamName:string) (position:int) = 
    eventStore.ReadEventAsync(streamName, position) 
    |> Async.AwaitTask 
    |> Async.RunSynchronously 

Bu sizin aradığınız şeyi almalı. İhtiyacınız olan işlevin fonksiyon imzasını çözme tekniğini ve ardından bu imzayla bir işlev aramayı unutmayın. Gelecekte bir LOT yardımcı olacaktır.

Güncelleme

: yorumlarında benim hata işaret için size Tarmil ederiz: Async.RunSynchronously C# 'ın await eşdeğer değildir olduğunu.Oldukça benzer, ancak şu anki iş parçacığını RunSynchronously engellediğinden emin olmak için bazı önemli incelikler var. (Eğer GUI dizisindeki aramak istemiyoruz.)

Güncelleme 2: Geçerli iş parçacığı engelleme olmadan bir zaman uyumsuz sonucunu beklemek istiyorum, genellikle böyle gider bir desen parçası:

onun sonucu
  • için
    1. Çağrı bazı zaman uyumsuz işlem
    2. bekleyin o sonucu

    o p yazmak için en iyi yolu şeyler yap şöyle attern geçerli:

    let equivalentOfAwait() = 
        async { 
         let! result = someAsyncOperation() 
         doSomethingWith result 
        } 
    

    yukarıda varsayar doSomethingWith döner unit, onun yan etkileri için diyoruz çünkü. elbette,

    let equivalentOfAwait() = 
        async { 
         let! result = someAsyncOperation() 
         let value = someCalculationWith result 
         return value 
        } 
    

    Veya: o bir değer döndürür yerine, yapmanız ediyorum someCalculationWith bir zaman uyumsuz işlem DEĞİL olduğunu varsayar

    let equivalentOfAwait() = 
        async { 
         let! result = someAsyncOperation() 
         return (someCalculationWith result) 
        } 
    

    . Bir çeşit sırayla hatta üç ya da dört zaman uyumsuz işlemleri - - Birlikte zincirine ikincisi birinci kişinin sonucunu kullanan iki zaman uyumsuz operasyonlar, ihtiyaç yerine, o zaman şu şekilde görünecektir:

    let equivalentOfAwait() = 
        async { 
         let! result1 = someAsyncOperation() 
         let! result2 = nextOperationWith result1 
         let! result3 = penultimateOperationWith result2 
         let! finalResult = finalOperationWith result3 
         return finalResult 
        } 
    
    let equivalentOfAwait() = 
        async { 
         let! result1 = someAsyncOperation() 
         let! result2 = nextOperationWith result1 
         let! result3 = penultimateOperationWith result2 
         return! (finalOperationWith result3) 
        } 
    

    Tüm bu fonksiyonlar

    'T son fonksiyonun dönüş tipi olacak bir Async<'T> oluşmasına neden olur: daha iyi olarak yazılabilir diye return ardından bu let! hariç

    , return! ile tamamen aynıdır async blok. aslında koşmak bu zaman uyumsuz bloklar, ya yaparsın için Async.RunSynchronously önceden de belirtildiği gibi, ya da çeşitli Async.Start işlevlerinden biri kullanabilir (Start, StartImmediate, StartAsTask, StartWithContinuations, vs.). Async.StartImmediate example, Async.SwitchToContext function hakkında biraz konuşur, bu da okumak isteyeceğiniz bir şey olabilir. Ama bundan daha fazlasını anlatmak için SynchronizationContext s ile yeterince tanıdık değilim.

  • +0

    Bu çivilenmiş. Teşekkürler. Ayrıca işaretçinin işlev imzalarına baktığınız için teşekkürler. –

    +3

    Uh, burada biraz yanlış bilgilendirme var. Yani, 'Async.RunSynchronously' en kesinlikle * değil * C#' s 'bekliyor' F # eşdeğerdir. Daha çok C# 'nun 'task.Wait()' gibi bir görevi vardır, yani görev tamamlanana kadar geçerli iş parçacığını engeller. bir "uyumsuzluk" bloğunda "let!", F # 'nin beklemesi "beklemesi" dir. – Tarmil

    +0

    @Tarmil - Bunu yakaladığınız için teşekkürler! Yanlış bilgilerimi düzeltdim; umarım cevaplamadan sonra cevap tamamen doğrudur. – rmunn

    İlgili konular