Kami mencoba mengembangkan aplikasi lintas platform untuk desktop (Windows dan Mac) menggunakan C #. Aplikasi ini berisi sejumlah besar hal-hal yang bergantung pada platform dan pimpinan tim kami ingin kami menulis semua kode itu dalam C #. Cara mudah untuk melakukan ini adalah dengan menulis pembungkus di C ++ dan hanya referensi perpustakaan di kode C # dan biarkan perpustakaan C ++ berurusan dengan hal-hal platform ... sayangnya, itu tidak terjadi.
Saya mencoba mengatur perpustakaan menggunakan Visual Studio untuk Mac. Saya berharap dapat menyediakan antarmuka tunggal di perpustakaan tunggal untuk memberikan akses ke perpustakaan teks ke ucapan asli pada platform saat ini - sebaiknya tanpa membuat dua majelis. Pustaka text-to-speech di C # untuk Windows tidak tersedia di Mac, jadi kami tidak benar-benar memiliki opsi alternatif selain menyediakan jembatan sendiri.
Saya senang dengan perpustakaan melakukan pencarian sistem operasi untuk menentukan sistem operasi mana yang sedang berjalan dan / atau mencoba memuat banyak perpustakaan asli dan hanya menggunakan perpustakaan mana yang akan dimuat.
Jika saya harus, memiliki satu proyek yang akan memungkinkan saya untuk menulis dua implementasi harus dilakukan. Saya belum menemukan cara untuk membuat proyek perpustakaan di Visual Studio untuk Mac, yang akan memungkinkan saya melakukannya. Satu-satunya jenis proyek yang akan memungkinkan banyak implementasi tampaknya mengharuskan implementasi baik untuk iOS atau untuk Android.
sumber
Jawaban:
Anda punya pertanyaan bagus. Mungkin ada beberapa trade-off dengan solusi Anda. Jawaban pamungkas sangat tergantung pada apa yang Anda maksudkan dengan ketergantungan platform. Misalnya, jika Anda memulai proses untuk memulai aplikasi eksternal dan Anda hanya beralih antara satu aplikasi dengan yang lain, Anda mungkin dapat mengatasinya tanpa terlalu banyak kerumitan. Jika Anda berbicara P / Panggil dengan perpustakaan asli, maka ada sedikit lagi yang harus dilakukan. Namun jika Anda menautkan dengan perpustakaan yang hanya ada pada satu platform, Anda mungkin perlu menggunakan banyak majelis.
Aplikasi eksternal
Anda mungkin tidak perlu menggunakan
#if
pernyataan dalam situasi ini. Hanya mengatur beberapa antarmuka, dan memiliki satu implementasi per platform. Gunakan pabrik untuk mendeteksi platform dan memberikan contoh yang tepat.Dalam beberapa kasus itu hanya biner yang dikompilasi untuk platform tertentu tetapi nama yang dapat dieksekusi dan semua parameter didefinisikan sama. Dalam hal ini adalah masalah menyelesaikan eksekusi yang tepat. Untuk aplikasi konverter audio massal yang dapat berjalan di Windows dan Linux, saya memiliki inisialisasi statis menyelesaikan nama biner.
Tidak ada yang mewah di sini. Kelas mode yang bagus.
P / Ajukan
P / Invoke agak sulit. Intinya adalah bahwa Anda perlu memastikan versi asli perpustakaan asli dimuat. Pada windows Anda akan P / Invoke
SetDllDirectory()
. Platform yang berbeda mungkin tidak memerlukan langkah itu. Jadi di sinilah segalanya menjadi berantakan. Anda mungkin perlu menggunakan#if
pernyataan untuk mengontrol panggilan mana yang digunakan untuk mengontrol penyelesaian jalur pustaka Anda - terutama jika Anda memasukkannya dalam paket distribusi Anda.Menautkan ke perpustakaan yang bergantung pada platform yang sama sekali berbeda
Pendekatan multi-penargetan sekolah tua mungkin bermanfaat di sini. Namun itu datang dengan banyak keburukan. Pada hari-hari ketika beberapa proyek berusaha untuk memiliki target DLL yang sama Silverlight, WPF, dan berpotensi UAP, Anda harus mengkompilasi aplikasi beberapa kali dengan tag kompilasi yang berbeda. Tantangan dengan masing-masing platform di atas adalah bahwa walaupun mereka berbagi konsep yang sama, platform tersebut cukup berbeda sehingga Anda harus mengatasi perbedaan-perbedaan itu. Di sinilah kita masuk ke neraka
#if
.Pendekatan ini juga memerlukan pengeditan tangan
.csproj
file untuk menangani referensi yang bergantung pada platform. Karena.csproj
file Anda adalah file MSBuild, sangat mungkin dilakukan dengan cara yang diketahui dan dapat diprediksi.#Jika neraka
Anda dapat menghidupkan dan mematikan bagian kode menggunakan
#if
pernyataan sehingga sangat efektif untuk menangani perbedaan kecil antara aplikasi. Di permukaan itu terdengar seperti ide yang bagus. Saya bahkan menggunakannya sebagai alat untuk menghidupkan dan mematikan visualisasi kotak terikat untuk men-debug kode gambar.Masalah nomor 1
#if
adalah bahwa tidak ada kode yang dimatikan yang dievaluasi oleh parser. Anda mungkin memiliki kesalahan sintaksis laten, atau lebih buruk, kesalahan logika menunggu Anda untuk mengkompilasi ulang perpustakaan. Ini menjadi lebih bermasalah dengan kode refactoring. Sesuatu yang sederhana seperti mengganti nama metode atau mengubah urutan parameter biasanya akan ditangani OK, tetapi karena parser tidak pernah mengevaluasi apa pun yang dimatikan oleh#if
pernyataan Anda tiba-tiba telah memecahkan kode yang tidak akan Anda lihat sampai Anda mengkompilasi ulang.Semua kode debug saya yang ditulis dengan cara itu harus ditulis ulang setelah serangkaian refactoring memecahkannya. Selama penulisan ulang, saya menggunakan kelas konfigurasi global untuk menghidupkan dan mematikan fitur-fitur itu. Itu membuatnya menjadi alat refactor proof, tetapi solusi seperti itu tidak membantu ketika API benar-benar berbeda.
Metode pilihan saya
Metode pilihan saya, berdasarkan banyak pelajaran menyakitkan yang dipelajari, dan bahkan berdasarkan contoh Microsoft sendiri, adalah dengan menggunakan banyak majelis.
Satu unit inti NetStandard akan mendefinisikan semua antarmuka dan berisi semua kode umum. Implementasi yang bergantung pada platform akan berada dalam perakitan terpisah yang akan menambah fitur ketika disertakan.
Pendekatan ini dicontohkan oleh API Konfigurasi baru dan arsitektur Identitas saat ini. Karena Anda memerlukan integrasi yang lebih spesifik, Anda cukup menambahkan rakitan baru itu. Rakitan itu juga menyediakan fungsi ekstensi untuk menggabungkan dirinya ke dalam pengaturan Anda. Jika Anda menggunakan pendekatan injeksi dependensi, metode ekstensi tersebut memungkinkan perpustakaan untuk mendaftarkan layanannya.
Ini adalah satu-satunya cara saya tahu untuk menghindari
#if
neraka, dan memuaskan lingkungan yang jauh berbeda.sumber
Microsoft.Extensions.Configuration
set API.