C++/CX

2015-09-09 14 views
5

'da C# async temsilci işlevi için nasıl bekleriz? C++ (farklı platformların paylaşılan kodu) arasındaki iletişim C# (Windows Evrensel Uygulaması) ile ilgilidir. Aşağıdakilerin C++'dan C#'a nasıl bir işlev çağrısı yaptığımız olduğunu biliyoruz. YukarıdaC++/CX

C#

class FooCS 
{ 
    FooCS() 
    { 
     FooC c = new ref FooC(); 
     c.m_GetSomeValueEvent = GetSomeValueEvent; 
     // Some other stuff ... 
    } 

    string GetSomeValueEvent() 
    { 
     // Some other stuff ... 
     return "Hello World"; 
    } 
} 

C++

public delegate Platform::String GetSomeValueEventHandler(); 

class FooC 
{ 
    public: 
    event GetSomeValueEventHandler^ m_GetSomeValueEvent; 
    void someFunction(){ 
     Platform::String^ str = m_GetSomeValueEvent(); 
     // Some other stuff ... 
    } 
} 

çok yalındır. Ama sorun şu ki GetSomeValueEvent() dizgisi veritabanından veri okuma gibi ağır bir görev yapmak ve ben async yapmak zorundayım.

async Task<string> GetSomeValueEvent() { 
     // Some other stuff ... 
     return "Hello World"; 
    } 

Şimdi burada soru geliyor: Nasıl bu temsilci işlevi iadesi için benim C++ kod beklemeye yapabilirim? Başka bir deyişle, aşağıdaki imza ne için değiştirilmelidir?

public delegate Platform::String GetSomeValueEventHandler(); 

Çevremdeyim ve bu sorun için doğru terminolojiyi bulamıyorum. Bunun imkansız olduğundan emin olduğunuzu biliyorsanız, en azından bilmek güzel olurdu.

string GetSomeValueEvent() { 
     // Convert a async method to non-async one 
     var val = someAsyncMethod().Result; 
     // Some other stuff ... 
     return "Hello World"; 
    } 

Sen GetSomeValueEvent kilitlenme önlemek için ana iş parçacığı üzerinde çalışmadığından emin olmalıyız: Sonunda


, bu yaptığımız budur.

cevap

3

UPD: Bir olaydan bir değer döndürmek gerçekten KÖTÜ bir fikirdir. Gözlenebilir paternin bir türünün, ancak tek bir gözlemcinin olduğu gibi diğer seçenekleri düşünün. @RaymondChen'den bahsedildiği gibi, asenkron olaylar için erteleme modelini kullanmak daha iyidir. Windows Runtime'da yaygın olarak kullanılan bir modeldir.

GetDeferral() yöntemini, özel bir deferral nesneyi döndüren olay hatalarınızı ekleyin. Bu nesne, kodunuzu eşzamansız bir işlemin tamamlandığını bildiren Complete() yöntemine sahip olmalıdır.

=================================

async anahtar sözcüğü aslında bir işlev prototipini değiştirmez. Bu nedenle, yalnızca orijinali (Task<string>) eşleştirmek için delegenizdeki dönüş değerini değiştirmeniz gerekir.

Ancak bir yakalama var: Windows Runtime, Task<> türüne sahip değil, bir .NET kitaplığı olan TPL'nin bir parçasıdır. Bunun yerine, Windows Çalışma Zamanı, zaman uyumsuz işlemleri temsil etmek için IAsyncOperation<> ve IAsyncAction kullanır.

public delegate Windows::Foundation::IAsyncOperation<Platform::String> GetSomeValueEventHandler(); 
  • Kullanım AsAsyncOperation() uzatma yöntemi Task<>IAsyncOperation<> dönüştürmek:

    async Task<string> GetSomeValueEvent() 
    { 
        // Some other stuff ... 
        return "Hello World"; 
    } 
    
    IAsyncOperation<string> GetSomeValueEventWrapper() 
    { 
        return GetSomeValueEvent().AsAsyncOperation(); 
    } 
    
    FooCS() 
    { 
        FooC c = new ref FooC(); 
        c.m_GetSomeValueEvent = GetSomeValueEventWrapper; 
        // Some other stuff ... 
    } 
    
    1. temsilcinin imzasını Alter: Yani burada

      yapmanız gerekenler

    +0

    İki olay aboneniz olduğunda bu, geri dönüş değeri için yalnızca bir tanesi kullanıldıkları için bozulur. Sınıf sadece bir abone görevi tamamlamak için bekleyecektir. Erteleme modelini kullanmak daha iyidir. –

    +0

    @RaymondChen Katılıyorum, bundan bahsetmeliydim. Ancak bir olay işleyicisinden bir değer döndürmek gerçekten kötü bir fikirdir ve dürüst bir şekilde, ertelemesiz patterin bunu nasıl çözeceğini bilmiyorum. –

    +0

    Windows Çalışma Zamanı modeli, bir 'GetDeferral' yöntemine ve sonuçları raporlamak için bazı mekanizmalara sahip bir' EventArgs' parametresini iletmektir. Her delege bir ertelenir, async eserini yapar, sonucu rapor etme mekanizması (belki bir 'SetResult' yöntemi, ya da sonucu bir koleksiyona ekleyerek) rapor eder, sonra erteleme işlemini tamamlar. Son erteleme tamamlandığında, arayan bildirilen tüm sonuçları denetler. –

    0

    Ne yapacağını bir C++ eşdeğer kullanmaktır: sadece sonucunu almak değil sizin için ne yapacağı

    var result = GetSomeValueEvent().GetAwaiter().GetResult(); 
    

    değil, aynı zamanda bu göreve meydana gelen bütün istisnalar Passthrough.