TL; DR - Saya mencoba merancang struktur data yang optimal untuk mendefinisikan unit dalam satuan ukuran.
A Unit of measure
pada dasarnya adalah value
(atau kuantitas) yang terkait dengan a unit
. Unit SI memiliki tujuh pangkalan atau dimensi. Yaitu: panjang, massa, waktu, arus listrik, suhu, jumlah zat (mol), dan intensitas cahaya.
Ini akan cukup mudah, tetapi ada sejumlah unit turunan serta tarif yang sering kita gunakan. Satuan gabungan contoh adalah Newton: kg * m / s^2
dan contoh laju adalah tons / hr
.
Kami memiliki aplikasi yang sangat bergantung pada unit tersirat. Kami akan menyematkan unit dalam nama variabel atau kolom. Tapi ini menciptakan masalah ketika kita perlu menentukan satuan ukuran dengan unit yang berbeda. Ya, kami dapat mengonversi nilai pada input dan tampilan tetapi ini menghasilkan banyak kode overhead yang ingin kami enkapsulasi di dalam kelasnya sendiri.
Ada sejumlah solusi pada codeplex dan lingkungan kolaboratif lainnya. Lisensi untuk proyek-proyek tersebut disetujui tetapi proyek itu sendiri biasanya berakhir terlalu ringan atau terlalu berat. Kami mengejar unicorn kami sendiri "benar."
Idealnya, saya bisa mendefinisikan satuan ukuran baru menggunakan sesuatu seperti ini:
UOM myUom1 = UOM baru (10, volt);
UOM myUom2 = UOM baru (43.2, Newton);
Tentu saja, kami menggunakan campuran unit Imperial dan SI berdasarkan kebutuhan klien kami.
Kami juga perlu menjaga struktur unit ini disinkronkan dengan tabel basis data masa depan sehingga kami dapat memberikan tingkat konsistensi yang sama di dalam data kami juga.
Apa cara terbaik untuk mendefinisikan unit, unit turunan, dan kurs yang perlu kita gunakan untuk membuat unit kelas pengukuran kita? Saya bisa melihat menggunakan satu atau lebih enum, tetapi itu bisa membuat frustasi bagi pengembang lain. Satu enum akan sangat besar dengan 200+ entri sedangkan beberapa enum bisa membingungkan berdasarkan unit SI vs Imperial dan rincian tambahan berdasarkan kategorisasi unit itu sendiri.
Contoh-contoh Enum yang menunjukkan beberapa kekhawatiran saya:
myUnits.Volt
myUnits.Newton
myUnits.meterSIUnit.meter
ImpUnit.foot DrvdUnit.Newton
DrvdUnitSI.Newton
DrvdUnitImp.FtLbs
Seperangkat unit yang kami gunakan didefinisikan dengan cukup baik dan ini adalah ruang yang terbatas. Kami benar-benar membutuhkan kemampuan untuk memperluas dan menambahkan unit atau tarif turunan baru ketika kami memiliki permintaan klien untuk mereka. Proyek ini dalam C # meskipun saya pikir aspek desain yang lebih luas berlaku untuk berbagai bahasa.
Salah satu perpustakaan yang saya lihat memungkinkan untuk input bebas bentuk unit melalui string. Kelas UOM mereka kemudian mengurai string dan mengatur hal-hal yang sesuai. Tantangan dengan pendekatan ini adalah bahwa hal itu memaksa pengembang untuk berpikir dan mengingat apa format string yang benar. Dan saya menjalankan risiko kesalahan runtime / pengecualian jika kita tidak menambahkan pemeriksaan tambahan dalam kode untuk memvalidasi string yang diteruskan dalam konstruktor.
Pustaka lain pada dasarnya menciptakan terlalu banyak kelas yang harus dikerjakan pengembang. Seiring dengan UOM yang setara itu disediakan DerivedUnit
dan RateUnit
dan seterusnya. Pada dasarnya, kode itu terlalu rumit untuk masalah yang kami pecahkan. Pustaka itu pada dasarnya akan membolehkan apa saja: kombinasi apa pun (yang sah di dunia unit) tapi kami senang lingkup masalah kami (menyederhanakan kode kami) dengan tidak mengizinkan setiap kombinasi yang mungkin.
Perpustakaan lain sangat sederhana dan bahkan tidak mempertimbangkan kelebihan operator misalnya.
Selain itu, saya tidak khawatir tentang upaya konversi yang salah (misalnya: volt ke meter). Devs adalah satu-satunya yang akan mengakses pada tingkat ini pada saat ini dan kita tidak perlu melindungi dari jenis kesalahan tersebut.
Jawaban:
Perpustakaan Boost untuk C ++ termasuk artikel tentang analisis dimensi yang menyajikan contoh implementasi unit penanganan ukuran.
Untuk meringkas: Satuan pengukuran direpresentasikan sebagai vektor, dengan masing-masing elemen vektor mewakili dimensi mendasar:
Unit yang diturunkan adalah kombinasi dari keduanya. Sebagai contoh, gaya (massa * jarak / waktu ^ 2) akan direpresentasikan sebagai
Unit Imperial versus SI dapat ditangani dengan menambahkan faktor konversi.
Implementasi ini bergantung pada C ++ - teknik khusus (menggunakan metaprogramming template untuk dengan mudah mengubah unit pengukuran yang berbeda menjadi tipe waktu kompilasi yang berbeda), tetapi konsep-konsep tersebut harus ditransfer ke bahasa pemrograman lain.
sumber
mpl::vector_c<int,1,0,0,0,0,0,0>
) bukan const; artikel ini menyajikan pendekatan consts pertama melalui penjelasan (dan saya mungkin tidak menjelaskannya dengan baik). Menggunakan const akan bekerja sebagai alternatif (Anda akan kehilangan beberapa jenis keamanan waktu kompilasi). Menggunakan namespace untuk menghindari polusi nama tentu saja merupakan pilihan.Saya baru saja merilis Units.NET di Github dan di NuGet .
Ini memberi Anda semua unit umum dan konversi. Ini ringan, unit diuji dan mendukung PCL.
Menuju pertanyaan Anda:
Saya belum melihat cawan suci solusi di domain ini. Ketika Anda menyatakan, itu bisa dengan mudah menjadi terlalu rumit atau terlalu bertele-tele untuk dikerjakan. Terkadang, yang terbaik adalah menjaga segala sesuatunya sederhana dan untuk kebutuhan saya pendekatan ini telah terbukti memadai.
Konversi eksplisit
Konversi dinamis
sumber
Truple<T1, T2, T3>(x, y, z)
Tuple
. Saya tidak dapat melihatUnitConverter
kelas Anda , tetapi IMO sepertinya memiliki fungsi yang sama denganTuple
kelas.Jika Anda dapat menarik beralih ke F # sebagai gantinya menggunakan C #, F # memiliki unit sistem pengukuran (diimplementasikan menggunakan metadata pada nilai-nilai) yang sepertinya cocok dengan apa yang Anda coba lakukan:
http://en.wikibooks.org/wiki/F_Sharp_Programming/Units_of_Measure
Terutama:
sumber
Important: Units of measure look like a data type, but they aren't. .NET's type system does not support the behaviors that units of measure have, such as being able to square, divide, or raise datatypes to powers. This functionality is provided by the F# static type checker at compile time, **but units are erased from compiled code**. Consequently, it is not possible to determine value's unit at runtime.
Berdasarkan kenyataan bahwa semua konversi yang diperlukan adalah konversi skala (kecuali jika Anda harus mendukung konversi suhu. Perhitungan di mana konversi melibatkan offset secara signifikan lebih kompleks), saya akan merancang sistem 'unit pengukuran' saya seperti ini:
Kelas yang
unit
mengandung faktor penskalaan, string untuk representasi tekstual unit dan referensi yang menjadiunit
skala. Representasi tekstual ada untuk tujuan tampilan dan referensi ke unit dasar untuk mengetahui unit mana hasilnya ketika melakukan matematika pada nilai-nilai dengan unit yang berbeda.Untuk setiap unit yang didukung, instance statis
unit
kelas disediakan.Kelas yang
UOM
berisi nilai dan referensi ke nilaiunit
. TheUOM
kelas menyediakan kelebihan beban operator untuk menambahkan / mengurangkan lainUOM
dan untuk mengalikan / membagi dengan nilai berdimensi.Jika penambahan / pengurangan dilakukan pada dua
UOM
dengan yang samaunit
, itu dilakukan secara langsung. Kalau tidak, kedua nilai dikonversi ke unit dasar masing-masing dan ditambahkan / dikurangi. Hasilnya dilaporkan berada di pangkalanunit
.Penggunaannya akan seperti
Karena operasi pada unit yang tidak kompatibel tidak dianggap sebagai masalah, saya belum mencoba untuk membuat tipe desain aman dalam hal itu. Dimungkinkan untuk menambahkan pemeriksaan runtime dengan memverifikasi bahwa dua unit merujuk ke unit dasar yang sama.
sumber
95F - 85F
? Apa20C - 15C
? Dalam kedua contoh, keduanyaUOM
akan memiliki hal yang samaunit
. Apakah pengurangan akan dilakukan secara langsung?10 F
dan5 C
. Perhitungan dilakukan secara langsung jika memungkinkan, untuk menghindari konversi yang tidak dibutuhkan. Akan sangat sepele untuk menambahkan metode konversi satuanUOM
, tetapi untuk konversi Celsius-Fahrenheit,unit
kelas harus diperluas dengan kemungkinan offset selain faktor penskalaan.95F - 85F
! =10F
.95F
oleh85F
? Setahu saya, Fahrenheit masih skala linear.20C - 15C = 5C
, maka kita katakan293.15K - 288.15K = 278.15K
, yang jelas salah.Pikirkan tentang apa yang dilakukan kode Anda, dan apa yang akan diizinkan. Memiliki penghitungan sederhana dengan semua unit yang memungkinkan di dalamnya memungkinkan saya untuk melakukan sesuatu seperti mengkonversi Volts ke meter. Itu jelas tidak berlaku untuk manusia, tetapi perangkat lunak akan dengan senang hati mencoba.
Saya melakukan sesuatu yang agak mirip dengan ini sekali, dan implementasi saya memiliki kelas dasar abstrak (panjang, berat, dll.) Yang semuanya diimplementasikan
IUnitOfMeasure
. Setiap kelas basis abstrak mendefinisikan jenis default (kelasLength
memiliki implementasi standar kelasMeter
) yang akan digunakan untuk semua pekerjaan konversi. KarenanyaIUnitOfMeasure
diimplementasikan dua metode yang berbeda,ToDefault(decimal)
danFromDefault(decimal)
.Angka aktual yang ingin saya bungkus adalah tipe generik yang menerima
IUnitOfMeasure
sebagai argumen generiknya. Mengatakan sesuatu sepertiMeasurement<Meter>(2.0)
memberi Anda keamanan tipe otomatis. Menerapkan konversi implisit yang tepat dan metode matematika pada kelas-kelas ini memungkinkan Anda untuk melakukan hal-hal sepertiMeasurement<Meter>(2.0) * Measurement<Inch>(12)
dan mengembalikan hasil dalam tipe default (Meter
). Saya tidak pernah mengerjakan unit turunan seperti Newtons; Saya hanya meninggalkan mereka sebagai Kilogram * Meter / Detik / Detik.sumber
Saya percaya jawabannya terletak pada respons Stack Overflow MarioVW terhadap :
Saya memiliki kebutuhan yang serupa untuk aplikasi saya.
Tuple
juga tidak berubah yang juga berlaku untuk benda-benda seperti Bobot dan Ukuran ... Seperti kata pepatah "satu liter per pon dunia di sekitar."sumber
Kode prototipe saya: http://ideone.com/x7hz7i
Poin desain saya:
sumber
Ada sebuah artikel yang baik dalam magazin sebuah unfourtunatly itu adalah dalam bahasa Jerman: http://www.dotnetpro.de/articles/onlinearticle1398.aspx
Ide dasar adalah memiliki kelas Unit seperti Panjang dengan BaseMeasurement. Kelas berisi faktor konversi, kelebihan operator, kelebihan ToString, pengurai string dan implementasi sebagai pengindeks. Kami bahkan telah mengimplementasikan tampilan Arsitektur tetapi tidak dirilis sebagai perpustakaan.
Jadi Anda melihat penggunaan dengan operator Tekanan atau hanya:
Tetapi seperti yang Anda katakan, saya juga tidak menemukan unicorn :)
sumber
Ini adalah raison d'etre dari
units
perintah Unix , yang melakukan semuanya menggunakan pendekatan data-file untuk menentukan hubungan.sumber
units
. Alasan utama unit tidak bekerja untuk solusi saya yang lebih luas adalah string bentuk bebas. Memang, itu memberikan pesan kesalahan sebagai imbalan, tetapi pendekatan ini menargetkan pengembang yang akan mengintegrasikan kode ini dengan aplikasi kami. String bentuk bebas menyajikan terlalu banyak peluang untuk kesalahan.units
file data. Cara mendefinisikan hubungan antara jumlah sangat bersih, dan mungkin berguna untuk masalah Anda.