Objek tangkas di C++/WinRT

Dalam sebagian besar kasus, instans kelas Windows Runtime dapat diakses dari utas apa pun (seperti kebanyakan objek C++ standar). Kelas Windows Runtime seperti itu tangkas. Hanya sejumlah kecil kelas Windows Runtime yang dikirim dengan Windows yang tidak tangkas, tetapi ketika Anda mengonsumsinya, Anda perlu mempertimbangkan model utas dan perilaku marshaling mereka (marshaling meneruskan data di seluruh batas apartemen). Ini adalah default yang baik untuk setiap objek Windows Runtime menjadi gesit, sehingga jenis C++/WinRT Anda sendiri gesit secara default.

Tetapi Anda dapat memilih keluar. Anda mungkin memiliki alasan kuat untuk mengharuskan objek jenis Anda berada, misalnya, di apartemen berulir tunggal tertentu. Ini biasanya ada hubungannya dengan persyaratan reentrancy. Tetapi semakin banyak, bahkan API antarmuka pengguna (UI) menawarkan objek tangkas. Secara umum, kelincahan adalah opsi yang paling sederhana dan paling berkinerja. Selain itu, ketika Anda menerapkan pabrik aktivasi, itu harus gesar bahkan jika kelas runtime yang sesuai tidak.

Catatan

Windows Runtime didasarkan pada COM. Dalam istilah COM, kelas tangkas terdaftar di ThreadingModel = Keduanya. Untuk informasi selengkapnya tentang model utas COM, dan apartemen, lihat Memahami dan Menggunakan Model Threading COM.

Contoh kode

Mari kita gunakan contoh implementasi kelas runtime untuk menunjukkan bagaimana C++/WinRT mendukung kelincahan.

#include <winrt/Windows.Foundation.h>

using namespace winrt;
using namespace Windows::Foundation;

struct MyType : winrt::implements<MyType, IStringable>
{
    winrt::hstring ToString(){ ... }
};

Karena kami belum memilih keluar, implementasi ini tangkas. Winrt::mengimplementasikan struktur dasar mengimplementasikan IAgileObject dan IMarshal. Implementasi IMarshal menggunakan CoCreateFreeThreadedMarshaler untuk melakukan hal yang benar untuk kode warisan yang tidak tahu tentang IAgileObject.

Kode ini memeriksa objek untuk kelincahan. Panggilan ke IUnknown::sebagai melemparkan pengecualian jika myimpl tidak gesit.

winrt::com_ptr<MyType> myimpl{ winrt::make_self<MyType>() };
winrt::com_ptr<IAgileObject> iagileobject{ myimpl.as<IAgileObject>() };

Daripada menangani pengecualian, Anda dapat memanggil IUnknown::try_as sebagai gantinya.

winrt::com_ptr<IAgileObject> iagileobject{ myimpl.try_as<IAgileObject>() };
if (iagileobject) { /* myimpl is agile. */ }

IAgileObject tidak memiliki metodenya sendiri, sehingga Anda tidak dapat melakukan banyak hal dengannya. Varian berikutnya, maka, lebih khas.

if (myimpl.try_as<IAgileObject>()) { /* myimpl is agile. */ }

IAgileObject adalah antarmuka penanda. Hanya keberhasilan atau kegagalan kueri untuk IAgileObject adalah sejauh mana informasi dan utilitas yang Anda dapatkan darinya.

Memilih keluar dari dukungan objek yang tangkas

Anda dapat memilih secara eksplisit untuk menolak dukungan objek agile dengan meneruskan struct penanda winrt::non_agile sebagai argumen templat ke kelas dasar Anda.

Jika Anda memperoleh langsung dari winrt::implements.

struct MyImplementation: implements<MyImplementation, IStringable, winrt::non_agile>
{
    ...
}

Jika Anda menulis kelas runtime.

struct MyRuntimeClass: MyRuntimeClassT<MyRuntimeClass, winrt::non_agile>
{
    ...
}

Tidak masalah di mana dalam paket parameter variadik struktur penanda muncul.

Apakah Anda menolak kelincahan atau tidak, Anda dapat mengimplementasikan IMarshal sendiri. Misalnya, Anda dapat menggunakan penanda winrt::non_agile untuk menghindari implementasi kelincahan default, dan mengimplementasikan IMarshal sendiri—mungkin untuk mendukung semantik marshal-by-value.

Referensi tangkas (winrt::agile_ref)

Jika Anda mengonsumsi objek yang tidak gesit, tetapi Anda perlu meneruskannya dalam beberapa konteks yang berpotensi gesit, maka salah satu opsinya adalah menggunakan templat struct winrt::agile_ref untuk mendapatkan referensi gesit ke instans jenis non-agile, atau ke antarmuka objek non-agile.

NonAgileType nonagile_obj;
winrt::agile_ref<NonAgileType> agile{ nonagile_obj };

Atau, Anda dapat menggunakan fungsi pembantu winrt::make_agile .

NonAgileType nonagile_obj;
auto agile{ winrt::make_agile(nonagile_obj) };

Dalam kedua kasus, agile sekarang dapat dengan bebas diteruskan ke utas di apartemen yang berbeda, dan digunakan di sana.

co_await resume_background();
NonAgileType nonagile_obj_again{ agile.get() };
winrt::hstring message{ nonagile_obj_again.Message() };

Panggilan agile_ref::get mengembalikan proksi yang dapat digunakan dengan aman dalam konteks utas tempat dipanggil .

API penting