Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Tip
Jika Anda telah membaca topik ini sebelumnya, dan Anda kembali ke topik ini dengan mempertimbangkan tugas tertentu, maka Anda dapat melompat ke bagian Temukan konten berdasarkan tugas yang Anda lakukan di topik ini.
Topik ini mendokumentasikan secara komprehensif detail teknis yang terlibat dalam mem-porting kode sumber dalam proyek C# ke padanannya dalam C++/WinRT.
Untuk studi kasus tentang porting salah satu sampel aplikasi Universal Windows Platform (UWP), lihat topik pendamping Memindahkan sampel Clipboard ke C++/WinRT dari C#. Anda dapat memperoleh latihan dan pengalaman melakukan porting dengan mengikuti panduan langkah demi langkah tersebut, serta melakukan porting pada sampelnya sendiri seiring Anda mengikutinya.
Cara mempersiapkan, dan apa yang diharapkan
Studi kasus Memindahkan sampel Clipboard ke C++/WinRT dari C# menggambarkan contoh jenis keputusan desain perangkat lunak yang akan Anda buat saat memindahkan proyek ke C++/WinRT. Jadi, ada baiknya mempersiapkan porting dengan mendapatkan pemahaman yang kuat tentang cara kerja kode yang ada. Dengan begitu, Anda akan mendapatkan gambaran umum yang baik tentang fungsionalitas aplikasi, dan struktur kode, dan kemudian keputusan yang Anda buat akan selalu membawa Anda maju, dan ke arah yang benar.
Terkait jenis perubahan dalam proses porting yang dapat diharapkan, Anda dapat mengelompokkannya ke dalam empat kategori.
-
Port proyeksi bahasa. Windows Runtime (WinRT) diproyeksikan ke dalam berbagai bahasa pemrograman. Setiap proyeksi bahasa tersebut dirancang agar terasa alami dalam bahasa pemrograman yang bersangkutan. Untuk C#, beberapa jenis Windows Runtime diproyeksikan sebagai jenis .NET. Jadi, misalnya Anda akan menerjemahkan System.Collections.Generic.IReadOnlyList<T> kembali ke Windows. Foundation.Collections.IVectorView<T>. Juga dalam C#, beberapa operasi Windows Runtime diproyeksikan sebagai fitur bahasa C# yang nyaman. Contohnya adalah bahwa dalam C# Anda menggunakan
+=sintaks operator untuk mendaftarkan delegasi penanganan peristiwa. Jadi Anda akan menerjemahkan fitur bahasa seperti itu kembali ke operasi mendasar yang sedang dilakukan (pendaftaran peristiwa, dalam contoh ini). -
Sintaks bahasa port. Banyak dari perubahan ini adalah transformasi mekanis sederhana, menggantikan satu simbol untuk yang lain. Misalnya, mengubah titik (
.) menjadi titik dua (::). -
Prosedur bahasa port. Beberapa di antaranya bisa menjadi perubahan sederhana dan berulang (seperti
myObject.MyPropertymyObject.MyProperty()). Yang lain membutuhkan perubahan yang lebih dalam (misalnya, memindahkan prosedur yang melibatkan penggunaan System.Text.StringBuilder ke salah satu yang melibatkan penggunaan std::wostringstream). -
Tugas terkait porting yang khusus untuk C++/WinRT. Detail tertentu dari Windows Runtime diurus secara implisit oleh C#, di belakang layar. Detail tersebut dilakukan secara eksplisit di C++/WinRT. Contohnya adalah Anda menggunakan
.idlfile untuk menentukan kelas runtime Anda.
Setelah indeks berbasis tugas yang mengikuti, bagian lainnya dalam topik ini disusun sesuai dengan taksonomi di atas.
Menemukan konten berdasarkan tugas yang Anda lakukan
| Tugas | Content |
|---|---|
| Menulis komponen Windows Runtime (WRC) | Fungsionalitas tertentu dapat dicapai (atau API tertentu yang disebut) hanya dengan C++. Anda dapat memperhitungkan fungsionalitas tersebut ke dalam C++/WinRT WRC, lalu menggunakan WRC dari (misalnya) aplikasi C#. Lihat Komponen Windows Runtime dengan C++/WinRT dan Jika Anda membuat kelas runtime dalam komponen Windows Runtime. |
| Adaptasikan metode asinkron | Sebaiknya, baris pertama dari metode asinkron dalam kelas runtime C++/WinRT adalah auto lifetime = get_strong(); (lihat Mengakses pointer this dengan aman dalam coroutine anggota kelas).Melakukan porting dari Task, lihat Aksi asinkron.Mem-porting dari Task<T>, lihat Operasi asinkron.Memindahkan dari async void, lihat metode fire-and-forget. |
| Mem-porting kelas | Pertama, tentukan apakah kelas perlu menjadi kelas runtime, atau apakah itu bisa menjadi kelas biasa. Untuk membantu Anda memutuskan hal itu, lihat bagian paling awal dari Membuat API dengan C++/WinRT. Kemudian, lihat tiga baris berikutnya di bawah ini. |
| Port kelas runtime | Kelas yang berbagi fungsionalitas di luar aplikasi C++, atau kelas yang digunakan dalam pengikatan data XAML. Lihat Jika Anda menulis kelas runtime dalam komponen Windows Runtime, atau Jika Anda menulis kelas runtime untuk direferensikan di antarmuka pengguna XAML Anda. Tautan tersebut menjelaskannya dengan lebih rinci, tetapi runtime class harus dideklarasikan dalam IDL. Jika project Anda sudah berisi file IDL (misalnya, Project.idl), kami sarankan Anda mendeklarasikan kelas runtime baru dalam file tersebut. Di IDL, deklarasikan metode dan anggota data apa pun yang akan digunakan di luar aplikasi Anda, atau yang akan digunakan di XAML. Setelah memperbarui file IDL, membangun kembali, dan melihat file stub yang dihasilkan (.h dan .cpp) di folder proyek Generated Files Anda (Dalam Penjelajah Solusi, dengan simpul proyek dipilih, pastikan Perlihatkan Semua File diaktifkan). Bandingkan file stub dengan file yang sudah ada di proyek Anda, menambahkan file atau menambahkan/memperbarui tanda tangan fungsi seperlunya. Sintaks file stub selalu benar, jadi kami sarankan Anda menggunakannya untuk meminimalkan kesalahan build. Setelah stub dalam proyek Anda cocok dengan yang ada di file stub, Anda dapat melanjutkan dan mengimplementasikannya dengan memindahkan kode C#. |
| Port kelas biasa | Lihat Jika Anda tidak membuat kelas runtime. |
| IDL Penulis |
Pengantar Microsoft Bahasa Definisi Antarmuka 3.0 Jika Anda menulis kelas runtime yang akan direferensikan di antarmuka pengguna XAML Anda Menggunakan objek dari markup XAML Menentukan kelas runtime Anda di IDL |
| Memindahkan koleksi |
Koleksi dengan C++/WinRT Membuat sumber data tersedia untuk markup XAML Kontainer asosiatif Akses anggota vektor |
| Pindahkan acara |
Delegat penangan event sebagai anggota kelas Mencabut delegasi penanganan aktivitas |
| Mem-porting sebuah metode | Dari C#: private async void SampleButton_Tapped(object sender, Microsoft.UI.Xaml.Input.TappedRoutedEventArgs e) { ... }Ke file C++/WinRT .h : fire_and_forget SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&);Ke dalam file C++/WinRT .cpp: fire_and_forget OcrFileImage::SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&) {...} |
| String port |
Penanganan string di C++/WinRT ToString Membangun string Tinju dan membuka kotak string |
| Konversi jenis (pengecoran jenis) | C#: o.ToString()C++/WinRT: to_hstring(static_cast<int>(o))Lihat juga ToString. C#: (Value)oC++/WinRT: unbox_value<Value>(o)Melempar jika pembukaan kotak gagal. Lihat juga Boxing dan unboxing. C#: o as Value? ?? fallbackC++/WinRT: unbox_value_or<Value>(o, fallback)Mengembalikan fallback jika pembatalan kotak gagal. Lihat juga Boxing dan unboxing. C#: (Class)oC++/WinRT: o.as<Class>()Melempar jika konversi gagal. C#: o as ClassC++/WinRT: o.try_as<Class>()Mengembalikan null jika konversi gagal. |
Perubahan yang melibatkan proyeksi bahasa
| Category | C# | C++/WinRT | Baca juga |
|---|---|---|---|
| Objek tanpa tipe |
object, atau System.Object |
Windows::Foundation::IInspectable | Memigrasikan metode EnableClipboardContentChangedNotifications |
| Namespace proyeksi | using System; |
using namespace Windows::Foundation; |
|
using System.Collections.Generic; |
using namespace Windows::Foundation::Collections; |
||
| Ukuran koleksi | collection.Count |
collection.Size() |
Memporting metode BuildClipboardFormatsOutputString |
| Jenis koleksi umum | IList<T>, dan Tambahkan untuk menambahkan elemen. | IVector<T>, dan Tambahkan untuk menambahkan elemen. Jika Anda menggunakan std::vector di bagian mana pun, maka gunakan push_back untuk menambahkan elemen. | |
| Jenis koleksi baca-saja | IReadOnlyList<T> | IVectorView<T> | Memporting metode BuildClipboardFormatsOutputString |
| Delegasi penangan kejadian sebagai anggota kelas | myObject.EventName += Handler; |
token = myObject.EventName({ get_weak(), &Class::Handler }); |
Melakukan porting metode EnableClipboardContentChangedNotifications |
| Mencabut delegasi penanganan aktivitas | myObject.EventName -= Handler; |
myObject.EventName(token); |
Memigrasikan metode EnableClipboardContentChangedNotifications |
| Kontainer asosiatif | IDictionary<K, V> | IMap<K, V> | |
| Akses anggota vektor | x = v[i];v[i] = x; |
x = v.GetAt(i);v.SetAt(i, x); |
Mendaftarkan/mencabut penanganan aktivitas
Di C++/WinRT, Anda memiliki beberapa opsi sintaks untuk mendaftarkan/membatalkan delegasi penanganan peristiwa, seperti yang dijelaskan dalam Menangani peristiwa dengan menggunakan delegasi di C++/WinRT. Lihat juga tentang mem-porting metode EnableClipboardContentChangedNotifications.
Terkadang, misalnya ketika penerima peristiwa (objek yang menangani peristiwa) akan dihancurkan, Anda mungkin ingin membatalkan penangan peristiwa agar sumber peristiwa (objek yang memicu peristiwa) tidak memanggil objek yang sudah dihancurkan. Lihat Mencabut delegasi terdaftar. Dalam kasus seperti itu, buat variabel anggota event_token untuk penanganan aktivitas Anda. Sebagai contoh, lihat Mem-porting metode EnableClipboardContentChangedNotifications.
Anda juga dapat mendaftarkan penanganan aktivitas di markup XAML.
<Button x:Name="OpenButton" Click="OpenButton_Click" />
Di C#, metode OpenButton_Click Anda dapat bersifat privat, dan XAML masih dapat menghubungkannya ke peristiwa ButtonBase.Click yang dinaikkan oleh OpenButton.
Di C++/WinRT, metode OpenButton_Click Anda harus publik dalam jenis implementasiAnda jika Anda ingin mendaftarkannya di markup XAML. Jika Anda mendaftarkan penanganan aktivitas hanya dalam kode imperatif, maka penanganan aktivitas tidak perlu publik.
namespace winrt::MyProject::implementation
{
struct MyPage : MyPageT<MyPage>
{
void OpenButton_Click(
winrt::Windows::Foundation::IInspectable const& sender,
winrt::Microsoft::UI::Xaml::RoutedEventArgs const& args);
}
};
Atau Anda dapat menjadikan halaman XAML yang mendaftarkan sebagai friend bagi tipe implementasi Anda, dan OpenButton_Click sebagai private.
namespace winrt::MyProject::implementation
{
struct MyPage : MyPageT<MyPage>
{
private:
friend MyPageT;
void OpenButton_Click(
winrt::Windows::Foundation::IInspectable const& sender,
winrt::Microsoft::UI::Xaml::RoutedEventArgs const& args);
}
};
Salah satu skenario terakhir adalah di mana proyek C# yang Anda porting mengikat ke penanganan aktivitas dari markup (untuk latar belakang lainnya tentang skenario tersebut, lihat Fungsi dalam x:Bind).
<Button x:Name="OpenButton" Click="{x:Bind OpenButton_Click}" />
Anda hanya bisa mengubah markup itu menjadi lebih sederhana Click="OpenButton_Click". Atau, jika mau, Anda dapat menyimpan markup tersebut apa adanya. Yang harus Anda lakukan untuk mendukungnya adalah mendeklarasikan penanganan aktivitas di IDL.
void OpenButton_Click(Object sender, Microsoft.UI.Xaml.RoutedEventArgs e);
Note
Deklarasikan fungsi tersebut sebagai void meskipun Anda mengimplementasikannya sebagai Fire and forget.
Perubahan yang melibatkan sintaks bahasa
| Category | C# | C++/WinRT | Baca juga |
|---|---|---|---|
| Pengubah akses | public \<member\> |
public:\<member\> |
Porting metode Button_Click |
| Mengakses anggota data | this.variable |
this->variable |
|
| Tindakan asinkron | async Task ... |
IAsyncAction ... |
Antarmuka IAsyncAction, Konkurensi, dan operasi asinkron dengan C++/WinRT |
| Operasi asinkron | async Task<T> ... |
IAsyncOperation<T> ... |
IAsyncOperation antarmuka, Konkurensi dan operasi asinkron dengan C++/WinRT |
| Metode Fire-and-forget (menyiratkan asinkron) | async void ... |
winrt::fire_and_forget ... |
Mem-porting metode CopyButton_Click, Jalankan lalu lupakan |
| Mengakses konstanta bernilai enumerasi | E.Value |
E::Value |
Memindahkan metode DisplayChangedFormats |
| Menunggu secara kooperatif | await ... |
co_await ... |
Porting metode CopyButton_Click |
| Kumpulan jenis yang diproyeksikan sebagai bidang privat | private List<MyRuntimeClass> myRuntimeClasses = new List<MyRuntimeClass>(); |
std::vector<MyNamespace::MyRuntimeClass>m_myRuntimeClasses; |
|
| Pembuatan GUID | private static readonly Guid myGuid = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1"); |
winrt::guid myGuid{ 0xC380465D, 0x2271, 0x428C, { 0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1} }; |
|
| Pemisah namespace | A.B.T |
A::B::T |
|
| Null | null |
nullptr |
Memindahkan metode UpdateStatus |
| Mendapatkan objek jenis | typeof(MyType) |
winrt::xaml_typename<MyType>() |
Porting properti Skenario |
| Deklarasi parameter untuk metode | MyType |
MyType const& |
Pengoperasian parameter |
| Deklarasi parameter untuk metode asinkron | MyType |
MyType |
Pengoperasian parameter |
| Memanggil metode statis | T.Method() |
T::Method() |
|
| String |
string, atau System.String |
winrt::hstring | Penanganan string di C++/WinRT |
| String literal (teks literal) | "a string literal" |
L"a string literal" |
Memindahkan konstruktor, Saat Ini, dan FEATURE_NAME |
| Tipe yang disimpulkan (atau dideduksi) | var |
auto |
Memporting metode BuildClipboardFormatsOutputString |
| Menggunakan direktif | using A.B.C; |
using namespace A::B::C; |
Memindahkan konstruktor, Saat Ini, dan FEATURE_NAME |
| Verbatim/string mentah literal | @"verbatim string literal" |
LR"(raw string literal)" |
Porting metode DisplayToast |
Note
Jika file header tidak berisi direktif using namespace untuk namespace tertentu, Anda harus menuliskan semua nama tipe dalam namespace tersebut secara lengkap; atau setidaknya menuliskannya dengan kualifikasi yang cukup agar kompilator dapat menemukannya. Misalnya, lihat Mem-porting metode DisplayToast.
Pemortingan kelas dan anggota
Anda harus memutuskan, untuk setiap jenis C#, apakah akan memindahkannya ke jenis Windows Runtime, atau ke kelas/struktur/enumerasi C++ biasa. Untuk informasi selengkapnya, dan contoh terperinci yang mengilustrasikan cara membuat keputusan tersebut, lihat Memindahkan sampel Clipboard ke C++/WinRT dari C#.
Properti C# biasanya menjadi fungsi pengakses, fungsi mutator, dan anggota data cadangan. Untuk informasi selengkapnya, dan contohnya, lihat Porting properti IsClipboardContentChangedEnabled.
Untuk bidang non-statis, jadikan mereka anggota data dari jenis implementasi Anda.
Bidang statis C# menjadi aksesor statis C++/WinRT dan/atau fungsi mutator. Untuk informasi selengkapnya, dan contohnya, lihat Memindahkan konstruktor, Saat Ini, dan FEATURE_NAME.
Untuk fungsi anggota, sekali lagi, Anda harus memutuskan untuk masing-masing apakah fungsi tersebut termasuk dalam IDL atau tidak, atau apakah itu fungsi anggota publik atau privat dari jenis implementasi Anda. Untuk informasi selengkapnya, dan contoh cara menentukan, lihat IDL untuk tipe MainPage.
Mem-porting markup XAML dan file aset
Dalam kasus Porting sampel Clipboard ke C++/WinRT dari C#, kami dapat menggunakan markup XAML yang sama (termasuk sumber daya) dan file aset di seluruh C# dan proyek C++/WinRT. Dalam beberapa kasus, pengeditan markup mungkin diperlukan untuk mencapainya. Lihat Menyalin XAML dan gaya yang diperlukan untuk menyelesaikan port MainPage.
Perubahan yang melibatkan prosedur dalam bahasa
| Category | C# | C++/WinRT | Baca juga |
|---|---|---|---|
| Manajemen seumur hidup dalam metode asinkron | N/A |
auto lifetime{ get_strong() }; atauauto lifetime = get_strong(); |
Porting metode CopyButton_Click |
| Pembuangan | using (var t = v) |
auto t{ v };t.Close(); // or let wrapper destructor do the work |
Porting metode CopyImage |
| Membuat objek | new MyType(args) |
MyType{ args } atauMyType(args) |
Porting properti Skenario |
| Membuat referensi yang tidak diinisialisasi | MyType myObject; |
MyType myObject{ nullptr }; atauMyType myObject = nullptr; |
Memindahkan konstruktor, Saat Ini, dan FEATURE_NAME |
| Membuat objek menjadi variabel dengan args | var myObject = new MyType(args); |
auto myObject{ MyType{ args } }; atau auto myObject{ MyType(args) }; atau auto myObject = MyType{ args }; atau auto myObject = MyType(args); atau MyType myObject{ args }; atau MyType myObject(args); |
Porting metode Footer_Click |
| Buat objek menjadi variabel tanpa arg | var myObject = new T(); |
MyType myObject; |
Memporting metode BuildClipboardFormatsOutputString |
| Bentuk singkat inisialisasi objek | var p = new FileOpenPicker{ViewMode = PickerViewMode.List}; |
FileOpenPicker p;p.ViewMode(PickerViewMode::List); |
|
| Operasi vektor massal | var p = new FileOpenPicker{FileTypeFilter = { ".png", ".jpg", ".gif" }}; |
FileOpenPicker p;p.FileTypeFilter().ReplaceAll({ L".png", L".jpg", L".gif" }); |
Porting metode CopyButton_Click |
| Lakukan iterasi pada koleksi | foreach (var v in c) |
for (auto&& v : c) |
Memporting metode BuildClipboardFormatsOutputString |
| Menangkap pengecualian | catch (Exception ex) |
catch (winrt::hresult_error const& ex) |
Porting metode PasteButton_Click |
| Detail pengecualian | ex.Message |
ex.message() |
Porting metode PasteButton_Click |
| Dapatkan nilai properti | myObject.MyProperty |
myObject.MyProperty() |
Porting metode NotifyUser |
| Mengatur nilai properti | myObject.MyProperty = value; |
myObject.MyProperty(value); |
|
| Menaikkan nilai properti | myObject.MyProperty += v; |
myObject.MyProperty(thing.Property() + v);Untuk string, beralihlah ke builder |
|
| ToString() | myObject.ToString() |
winrt::to_hstring(myObject) |
ToString() |
| String bahasa ke string Windows Runtime | N/A | winrt::hstring{ s } |
|
| Perakitan string | StringBuilder builder;builder.Append(...); |
std::wostringstream builder;builder << ...; |
Membangun string |
| Interpolasi string | $"{i++}) {s.Title}" |
winrt::to_hstring, dan/atau winrt::hstring::operator+ | Porting metode OnNavigatedTo |
| String kosong untuk perbandingan | System.String.Empty | winrt::hstring::empty | Memindahkan metode UpdateStatus |
| Membuat string kosong | var myEmptyString = String.Empty; |
winrt::hstring myEmptyString{ L"" }; |
|
| Operasi kamus | map[k] = v; // replaces any existingv = map[k]; // throws if not presentmap.ContainsKey(k) |
map.Insert(k, v); // replaces any existingv = map.Lookup(k); // throws if not presentmap.HasKey(k) |
|
| Konversi tipe (hasilkan pengecualian jika gagal) | (MyType)v |
v.as<MyType>() |
Porting metode Footer_Click |
| Konversi tipe (null jika gagal) | v as MyType |
v.try_as<MyType>() |
Memindahkan metode PasteButton_Click |
| Elemen XAML dengan x:Name adalah properti | MyNamedElement |
MyNamedElement() |
Memindahkan konstruktor, Saat Ini, dan FEATURE_NAME |
| Beralih ke thread UI | CoreDispatcher.RunAsync | DispatcherQueue.TryEnqueue, atau winrt::resume_foreground | Mem-porting metode NotifyUser, dan mem-porting metode HistoryAndRoaming |
| Konstruksi elemen UI dalam kode imperatif di halaman XAML | Lihat konstruksi elemen UI | Lihat konstruksi elemen UI |
Bagian berikut masuk ke detail lebih lanjut mengenai beberapa item dalam tabel.
Pembuatan elemen UI
Contoh kode ini menunjukkan konstruksi elemen UI dalam kode imperatif halaman XAML.
var myTextBlock = new TextBlock()
{
Text = "Text",
Style = (Microsoft.UI.Xaml.Style)this.Resources["MyTextBlockStyle"]
};
TextBlock myTextBlock;
myTextBlock.Text(L"Text");
myTextBlock.Style(
winrt::unbox_value<Microsoft::UI::Xaml::Style>(
Resources().Lookup(
winrt::box_value(L"MyTextBlockStyle")
)
)
);
ToString()
Jenis C# menyediakan metode Object.ToString .
int i = 2;
var s = i.ToString(); // s is a System.String with value "2".
C++/WinRT tidak secara langsung menyediakan fasilitas ini, tetapi Anda dapat beralih ke alternatif.
int i{ 2 };
auto s{ std::to_wstring(i) }; // s is a std::wstring with value L"2".
C++/WinRT juga mendukung winrt::to_hstring untuk sejumlah jenis yang terbatas. Anda harus menambahkan kelebihan beban untuk jenis tambahan apa pun yang ingin Anda stringifikasi.
| Bahasa | Konversi int menjadi string | Ubah enum menjadi string |
|---|---|---|
| C# | string result = "hello, " + intValue.ToString();string result = $"hello, {intValue}"; |
string result = "status: " + status.ToString();string result = $"status: {status}"; |
| C++/WinRT | hstring result = L"hello, " + to_hstring(intValue); |
// must define overload (see below)hstring result = L"status: " + to_hstring(status); |
Jika Anda mengonversi enum menjadi string, Anda perlu menyediakan implementasi winrt::to_hstring.
namespace winrt
{
hstring to_hstring(StatusEnum status)
{
switch (status)
{
case StatusEnum::Success: return L"Success";
case StatusEnum::AccessDenied: return L"AccessDenied";
case StatusEnum::DisabledByPolicy: return L"DisabledByPolicy";
default: return to_hstring(static_cast<int>(status));
}
}
}
Hasil konversi menjadi string ini sering dimanfaatkan secara implisit oleh mekanisme data binding.
<TextBlock>
You have <Run Text="{Binding FlowerCount}"/> flowers.
</TextBlock>
<TextBlock>
Most recent status is <Run Text="{x:Bind LatestOperation.Status}"/>.
</TextBlock>
Pengikatan ini akan menerapkan winrt::to_hstring pada properti yang diikat. Dalam kasus contoh kedua ( StatusEnum), Anda harus menyediakan kelebihan beban Winrt::to_hstring Anda sendiri, jika tidak, Anda akan mendapatkan kesalahan kompilator.
Lihat juga Porting metode Footer_Click.
Pembuatan string
Untuk pembuatan string, C# memiliki jenis StringBuilder bawaan.
| Category | C# | C++/WinRT |
|---|---|---|
| Perakitan string | StringBuilder builder;builder.Append(...); |
std::wostringstream builder;builder << ...; |
| Menambahkan string Windows Runtime dengan mempertahankan nilai null | builder.Append(s); |
builder << std::wstring_view{ s }; |
| Menambahkan baris baru | builder.Append(Environment.NewLine); |
builder << std::endl; |
| Mengakses hasil | s = builder.ToString(); |
ws = builder.str(); |
Lihat juga Porting metode BuildClipboardFormatsOutputString, dan Porting metode DisplayChangedFormats.
Menjalankan kode pada utas UI utama
Contoh ini diambil dari sampel pemindai Barcode.
Ketika Anda ingin melakukan pekerjaan pada utas UI utama dalam proyek C#, Anda biasanya menggunakan metode DispatcherQueue.TryEnqueue (atau CoreDispatcher.RunAsync yang lebih lama di UWP). Seperti inilah polanya dalam C#.
private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
{
DispatcherQueue.TryEnqueue(() =>
{
// Do work on the main UI thread here.
});
}
Jauh lebih mudah untuk mengekspresikannya di C++/WinRT. Perhatikan bahwa kita menerima parameter secara nilai dengan asumsi bahwa kita akan perlu mengaksesnya setelah titik penangguhan eksekusi pertama (co_await, dalam hal ini). Untuk informasi selengkapnya, lihat Parameter-passing.
winrt::fire_and_forget Watcher_Added(DeviceWatcher sender, winrt::DeviceInformation args)
{
co_await DispatcherQueue();
// Do work on the main UI thread here.
}
Jika Anda perlu melakukan pekerjaan dengan prioritas selain default, lihat fungsi winrt::resume_foreground , yang memiliki kelebihan beban yang mengambil prioritas. Untuk contoh kode yang menunjukkan cara menunggu panggilan ke winrt::resume_foreground, lihat Pemrograman dengan afinitas utas.
Tugas terkait porting yang khusus untuk C++/WinRT
Menentukan kelas runtime Anda di IDL
Lihat IDL untuk tipe MainPage, dan Konsolidasikan file .idlAnda.
Sertakan file header namespace C++/WinRT Windows yang Anda butuhkan
Di C++/WinRT, setiap kali Anda ingin menggunakan jenis dari namespace Windows, Anda perlu menyertakan file header namespace C++/WinRT Windows yang sesuai. Misalnya, lihat Mem-porting metode NotifyUser.
Boxing dan Unboxing
C# secara otomatis mengetikkan skalar ke dalam objek. C++/WinRT mengharuskan Anda untuk memanggil fungsi winrt::box_value secara eksplisit. Kedua bahasa mengharuskan Anda untuk membuka kotak secara eksplisit. Lihat Tinju dan buka kotak dengan C++/WinRT.
Dalam tabel berikut, kita akan menggunakan definisi ini.
| C# | C++/WinRT |
|---|---|
int i; |
int i; |
string s; |
winrt::hstring s; |
object o; |
IInspectable o; |
| Operation | C# | C++/WinRT |
|---|---|---|
| Boxing | o = 1;o = "string"; |
o = box_value(1);o = box_value(L"string"); |
| Pembukaan Kotak | i = (int)o;s = (string)o; |
i = unbox_value<int>(o);s = unbox_value<winrt::hstring>(o); |
C++/CX dan C# memunculkan pengecualian jika Anda mencoba melakukan unboxing pada penunjuk null menjadi tipe nilai. C++/WinRT menganggap ini sebagai kesalahan pemrograman, dan mengalami crash. Di C++/WinRT, gunakan fungsi winrt::unbox_value_or jika Anda ingin menangani kasus di mana objek bukan dari jenis yang Anda pikirkan.
| Scenario | C# | C++/WinRT |
|---|---|---|
| Lakukan unboxing pada integer yang diketahui | i = (int)o; |
i = unbox_value<int>(o); |
| Jika o null | System.NullReferenceException |
Kecelakaan |
| Jika o bukan int yang dibungkus | System.InvalidCastException |
Kecelakaan |
| Batalkan kotak masuk, gunakan fallback jika null; crash jika ada yang lain | i = o != null ? (int)o : fallback; |
i = o ? unbox_value<int>(o) : fallback; |
| Batalkan kotak int jika memungkinkan; gunakan fallback untuk hal lain | i = as int? ?? fallback; |
i = unbox_value_or<int>(o, fallback); |
Misalnya, lihat Porting metode OnNavigatedTo, dan Porting metode Footer_Click.
Tinju dan membuka kotak string
String dalam beberapa hal adalah sebuah tipe nilai, namun dalam hal lain merupakan tipe referensi. C# dan C++/WinRT memperlakukan string secara berbeda.
Tipe ABI HSTRING adalah pointer ke string dengan jumlah referensi yang dihitung. Tetapi tidak berasal dari IInspectable, jadi itu bukan objek secara teknis. Selain itu, HSTRING null mewakili string kosong. Proses boxing untuk objek yang tidak diturunkan dari IInspectable dilakukan dengan membungkusnya dalam IReference<T>, dan Windows Runtime menyediakan implementasi standar dalam bentuk objek PropertyValue (jenis kustom dilaporkan sebagai PropertyType::OtherType).
C# mewakili string Windows Runtime sebagai jenis referensi; sementara C++/WinRT memproyeksikan string sebagai jenis nilai. Ini berarti bahwa string null kotak dapat memiliki representasi yang berbeda tergantung bagaimana Anda sampai di sana.
| Behavior | C# | C++/WinRT |
|---|---|---|
| Deklarasi | object o;string s; |
IInspectable o;hstring s; |
| Kategori jenis string | Jenis referensi | Jenis nilai |
| null HSTRING diproyeksikan sebagai | "" |
hstring{} |
Apakah null dan "" identik? |
No | Yes |
| Keabsahan null | s = null;s.Length melempar NullReferenceException |
s = hstring{};s.size() == 0 (valid) |
| Jika Anda menetapkan string null ke objek | o = (string)null;o == null |
o = box_value(hstring{});o != nullptr |
Jika Anda menetapkan "" ke objek |
o = "";o != null |
o = box_value(hstring{L""});o != nullptr |
Tinju dasar dan pembukaan kotak.
| Operation | C# | C++/WinRT |
|---|---|---|
| Beri kotak pada teks | o = s;String kosong menjadi objek non-null. |
o = box_value(s);String kosong menjadi objek non-null. |
| Batalkan kotak string yang diketahui | s = (string)o;Objek null menjadi string null. InvalidCastException jika nilainya bukan string. |
s = unbox_value<hstring>(o);Objek null mengalami crash. Crash jika nilainya bukan string. |
| Batalkan kotak kemungkinan string | s = o as string;Objek null atau non-string menjadi string null. OR s = o as string ?? fallback;Null atau bukan string akan menjadi nilai cadangan. String kosong dipertahankan. |
s = unbox_value_or<hstring>(o, fallback);Null atau bukan string akan menjadi nilai cadangan. String kosong dipertahankan. |
Membuat kelas tersedia untuk ekstensi markup {Binding}
Jika Anda bermaksud menggunakan ekstensi markup {Binding} untuk mengikat data ke tipe data Anda, lihat objek Binding yang dideklarasikan menggunakan {Binding}.
Mengkonsumsi objek dari markup XAML
Dalam proyek C#, Anda dapat mengakses anggota privat dan elemen yang diberi nama dari markup XAML. Tetapi di C++/WinRT, semua entitas yang digunakan dengan menggunakan ekstensi markup XAML {x:Bind} harus diekspos secara publik di IDL.
Selain itu, pengikatan ke Boolean ditampilkan sebagai true atau false di C#, tetapi di C++/WinRT ditampilkan sebagai Windows.Foundation.IReference`1<Boolean>.
Untuk informasi selengkapnya, dan contoh kode, lihat Menggunakan objek dari markup.
Membuat sumber data tersedia untuk markup XAML
Di C++/WinRT versi 2.0.190530.8 atau yang lebih baru, winrt::single_threaded_observable_vector membuat vektor yang dapat diamati yang mendukung IObservableVector<T> dan IObservableVector<IInspectable>. Misalnya, lihat Porting properti Skenario.
Anda dapat menulis file Midl Anda (.idl) seperti ini (juga lihat Memperhitungkan kelas runtime ke dalam file Midl (.idl)).
namespace Bookstore
{
runtimeclass BookSku { ... }
runtimeclass BookstoreViewModel
{
Windows.Foundation.Collections.IObservableVector<BookSku> BookSkus{ get; };
}
runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
{
MainPage();
BookstoreViewModel MainViewModel{ get; };
}
}
Dan implementasikan seperti ini.
// BookstoreViewModel.h
...
struct BookstoreViewModel : BookstoreViewModelT<BookstoreViewModel>
{
BookstoreViewModel()
{
m_bookSkus = winrt::single_threaded_observable_vector<Bookstore::BookSku>();
m_bookSkus.Append(winrt::make<Bookstore::implementation::BookSku>(L"To Kill A Mockingbird"));
}
Windows::Foundation::Collections::IObservableVector<Bookstore::BookSku> BookSkus();
{
return m_bookSkus;
}
private:
Windows::Foundation::Collections::IObservableVector<Bookstore::BookSku> m_bookSkus;
};
...
Untuk informasi selengkapnya, lihat Kontrol item XAML; ikat ke koleksi C++/WinRT, dan Koleksi dengan C++/WinRT.
Membuat sumber data tersedia untuk markup XAML (sebelum C++/WinRT 2.0.190530.8)
Pengikatan data XAML mengharuskan sumber item mengimplementasikan IIterable<IInspectable>, serta salah satu dari kombinasi antarmuka berikut.
- IObservableVector<IInspectable>
- IBindableVector dan INotifyCollectionChanged
- IBindableVector dan IBindableObservableVector
- IBindableVector dengan sendirinya (tidak akan merespons perubahan)
- IVector<IInspectable>
- IBindableIterable (akan mengiterasi dan menyimpan elemen dalam koleksi privat)
Antarmuka generik seperti IVector<T> tidak dapat dideteksi saat runtime. Setiap IVector<T> memiliki pengidentifikasi antarmuka (IID) yang berbeda, yang merupakan fungsi T. Setiap pengembang dapat memperluas set T secara sembrono, jadi dengan jelas kode pengikatan XAML tidak pernah dapat mengetahui set lengkap untuk kueri. Pembatasan itu bukan masalah untuk C# karena setiap objek CLR yang mengimplementasikan IEnumerable<T> secara otomatis menerapkan IEnumerable. Pada tingkat ABI, itu berarti bahwa setiap objek yang mengimplementasikan IObservableVector<T> secara otomatis mengimplementasikan IObservableVector<IInspectable>.
C++/WinRT tidak menawarkan jaminan tersebut. Jika kelas runtime C++/WinRT mengimplementasikan IObservableVector<T>, maka kami tidak dapat berasumsi bahwa implementasi IObservableVector<IInspectable> juga disediakan.
Oleh karena itu, berikut tampilan contoh sebelumnya yang perlu terlihat seperti ini.
...
runtimeclass BookstoreViewModel
{
// This is really an observable vector of BookSku.
Windows.Foundation.Collections.IObservableVector<Object> BookSkus{ get; };
}
Dan implementasinya.
// BookstoreViewModel.h
...
struct BookstoreViewModel : BookstoreViewModelT<BookstoreViewModel>
{
BookstoreViewModel()
{
m_bookSkus = winrt::single_threaded_observable_vector<Windows::Foundation::IInspectable>();
m_bookSkus.Append(winrt::make<Bookstore::implementation::BookSku>(L"To Kill A Mockingbird"));
}
// This is really an observable vector of BookSku.
Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable> BookSkus();
{
return m_bookSkus;
}
private:
Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable> m_bookSkus;
};
...
Jika anda perlu mengakses objek di m_bookSkus, maka anda harus QI mereka kembali ke Bookstore::BookSku.
Widget MyPage::BookstoreViewModel(winrt::hstring title)
{
for (auto&& obj : m_bookSkus)
{
auto bookSku = obj.as<Bookstore::BookSku>();
if (bookSku.Title() == title) return bookSku;
}
return nullptr;
}
Kelas turunan
Agar dapat mewarisi dari kelas runtime, kelas dasar harus dapat dikomposisikan. C# tidak mengharuskan Anda melakukan langkah-langkah khusus untuk membuat kelas Anda dapat dikomposisikan, tetapi C++/WinRT mengharuskannya. Anda menggunakan kata kunci yang tidak disegel untuk menunjukkan bahwa Anda ingin kelas Anda dapat digunakan sebagai kelas dasar.
unsealed runtimeclass BasePage : Microsoft.UI.Xaml.Controls.Page
{
...
}
runtimeclass DerivedPage : BasePage
{
...
}
Dalam file header untuk jenis implementasi, Anda harus menyertakan file header kelas dasar sebelum menyertakan header yang dibuat secara otomatis untuk kelas turunan. Jika tidak, Anda akan menemui kesalahan seperti "Penggunaan tipe ini sebagai ekspresi tidak sah".
// DerivedPage.h
#include "BasePage.h" // This comes first.
#include "DerivedPage.g.h" // Otherwise this header file will produce an error.
namespace winrt::MyNamespace::implementation
{
struct DerivedPage : DerivedPageT<DerivedPage>
{
...
}
}
API penting
Topik terkait
Windows developer