Bagaimana cara memeriksa apakah objek yang diberikan dapat dibatalkan dengan kata lain cara menerapkan metode berikut ...
bool IsNullableValueType(object o)
{
...
}
EDIT: Saya mencari jenis nilai yang dapat dibatalkan. Saya tidak memiliki tipe ref dalam pikiran.
//Note: This is just a sample. The code has been simplified
//to fit in a post.
public class BoolContainer
{
bool? myBool = true;
}
var bc = new BoolContainer();
const BindingFlags bindingFlags = BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Instance
;
object obj;
object o = (object)bc;
foreach (var fieldInfo in o.GetType().GetFields(bindingFlags))
{
obj = (object)fieldInfo.GetValue(o);
}
obj sekarang merujuk ke objek bertipe bool
( System.Boolean
) dengan nilai sama dengan true
. Yang benar-benar saya inginkan adalah objek bertipeNullable<bool>
Jadi sekarang sebagai pekerjaan di sekitar saya memutuskan untuk memeriksa apakah o dapat dibatalkan dan membuat pembungkus nullable di sekitar obj.
Jawaban:
Ada dua jenis nullable -
Nullable<T>
dan tipe referensi.Jon telah mengoreksi saya bahwa sulit untuk mendapatkan ketik jika kotak, tetapi Anda bisa dengan obat generik: - jadi bagaimana kalau di bawah ini. Ini sebenarnya tipe pengujian
T
, tetapi menggunakanobj
parameter murni untuk inferensi tipe generik (untuk membuatnya mudah dipanggil) - itu akan bekerja hampir identik tanpaobj
param, meskipun.Tapi ini tidak akan bekerja dengan baik jika Anda telah mengotakkan nilai ke variabel objek.
Dokumentasi Microsoft: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type
sumber
T
parameter generik dibatasi olehT : struct
, makaT
tidak bolehNullable<>
, jadi Anda tidak perlu memeriksa dalam kasus itu! Saya tahu jenisnyaNullable<>
adalah sebuah struct, tetapi dalam C # batasannyawhere T : struct
secara khusus mengecualikan tipe-nilai yang dapat dibatalkan. Spesifikasi mengatakan: "Perhatikan bahwa meskipun diklasifikasikan sebagai tipe nilai, tipe nullable (§4.1.10) tidak memenuhi batasan tipe nilai."Ada solusi yang sangat sederhana menggunakan kelebihan metode
http://deanchalk.com/is-it-nullable/
kutipan:
kemudian
sumber
True
akan dikembalikan.System.Nullable<>
). Jika Anda berkataobject g = e;
dan kemudianValueTypeHelper.IsNullable(g)
, apa yang Anda harapkan untuk dapatkan?Pertanyaan "Bagaimana cara memeriksa apakah suatu jenis dapat dibatalkan?" sebenarnya "Bagaimana memeriksa apakah suatu tipe adalah
Nullable<>
?", yang dapat digeneralisasi menjadi "Bagaimana memeriksa apakah suatu tipe adalah tipe yang dikonstruksi dari beberapa tipe generik?", sehingga tidak hanya menjawab pertanyaan "ApakahNullable<int>
aNullable<>
?", tetapi juga "ApakahList<int>
aList<>
?".Sebagian besar solusi yang disediakan menggunakan
Nullable.GetUnderlyingType()
metode ini, yang jelas hanya akan bekerja dengan caseNullable<>
. Saya tidak melihat solusi reflektif umum yang akan bekerja dengan semua jenis generik, jadi saya memutuskan untuk menambahkannya di sini untuk anak cucu, meskipun pertanyaan ini sudah dijawab sejak lama.Untuk memeriksa apakah suatu jenis
Nullable<>
menggunakan bentuk refleksi, Anda harus terlebih dahulu mengubah tipe generik yang Anda buat, misalnyaNullable<int>
, ke definisi tipe generikNullable<>
,. Anda dapat melakukannya dengan menggunakanGetGenericTypeDefinition()
metodeType
kelas. Anda kemudian dapat membandingkan jenis yang dihasilkan denganNullable<>
:Hal yang sama dapat diterapkan untuk semua jenis generik:
Beberapa tipe mungkin terlihat sama, tetapi jumlah argumen tipe yang berbeda berarti tipe yang sama sekali berbeda.
Karena
Type
objek dipakai sekali per jenis, Anda dapat memeriksa kesetaraan referensi di antara mereka. Jadi, jika Anda ingin memeriksa apakah dua objek memiliki definisi tipe generik yang sama, Anda dapat menulis:Jika Anda ingin memeriksa apakah suatu objek nullable, bukan a
Type
, maka Anda dapat menggunakan teknik di atas bersama dengan solusi Marc Gravell untuk membuat metode yang agak sederhana:sumber
Nullable.GetUnderlyingType()
yang sudah disediakan oleh kerangka kerja. Mengapa tidak hanya menggunakan metode dalam kerangka kerja? Nah, kamu harus. Lebih jelas, lebih ringkas dan lebih teruji. Tetapi dalam posting saya, saya mencoba mengajarkan bagaimana menggunakan refleksi untuk mendapatkan informasi yang Anda inginkan, sehingga seseorang dapat menerapkannya ke semua jenis (dengan menggantitypeof(Nullable<>)
dengan jenis lain). Jika Anda melihat sumberGetUnderlyingType()
(asli atau didekompilasi), Anda akan melihatnya sangat mirip dengan kode saya.Ini bekerja untuk saya dan tampaknya sederhana:
Untuk jenis nilai:
sumber
Nah, Anda bisa menggunakan:
... tetapi sebuah objek itu sendiri tidak dapat dibatalkan atau sebaliknya - suatu tipe adalah. Bagaimana Anda berencana menggunakan ini?
sumber
Cara paling sederhana yang bisa saya pikirkan adalah:
sumber
Nullable
, tetapi dengan semantik yang berbeda. Dalam situasi saya, saya harus mendukungnull
sebagai nilai yang valid dan juga tidak mendukung nilai sama sekali. Jadi suatuOptional
jenis menciptakan . Karena itu diperlukan untuk mendukungnull
nilai-nilai, saya juga harus menerapkan kode untuk menanganiNullable
nilai-nilai sebagai bagian dari implementasi saya. Dari situlah kode ini berasal.Ada dua masalah di sini: 1) pengujian untuk melihat apakah suatu Jenis dapat dibatalkan; dan 2) pengujian untuk melihat apakah suatu objek mewakili Tipe yang dapat dibatalkan.
Untuk edisi 1 (menguji Tipe), inilah solusi yang saya gunakan dalam sistem saya sendiri: Solusi TypeIsNullable-check
Untuk edisi 2 (menguji suatu objek), solusi Dean Chalk di atas berfungsi untuk tipe nilai, tetapi itu tidak berfungsi untuk tipe referensi, karena menggunakan <T> yang berlebihan selalu menghasilkan false. Karena tipe referensi secara inheren nullable, pengujian tipe referensi harus selalu mengembalikan true. Silakan lihat catatan [Tentang "nullability"] di bawah untuk penjelasan tentang semantik ini. Jadi, inilah modifikasi saya untuk pendekatan Dean:
Dan inilah modifikasi saya pada kode uji klien untuk solusi di atas:
Alasan saya memodifikasi pendekatan Dean di IsObjectNullable <T> (Tt) adalah bahwa pendekatan aslinya selalu kembali false untuk tipe referensi. Karena metode seperti IsObjectNullable harus dapat menangani nilai tipe referensi dan karena semua tipe referensi secara inheren nullable, maka jika salah satu tipe referensi atau nol dilewatkan, metode tersebut harus selalu mengembalikan true.
Dua metode di atas dapat diganti dengan metode tunggal berikut dan mencapai hasil yang sama:
Namun, masalah dengan pendekatan metode tunggal terakhir ini adalah bahwa kinerja menderita ketika parameter <T> Nullable digunakan. Dibutuhkan lebih banyak waktu prosesor untuk mengeksekusi baris terakhir metode tunggal ini daripada yang memungkinkan kompiler untuk memilih kelebihan metode kedua yang ditunjukkan sebelumnya ketika parameter tipe-Nullable <T> digunakan dalam panggilan IsObjectNullable. Oleh karena itu, solusi optimal adalah dengan menggunakan pendekatan dua metode yang diilustrasikan di sini.
CAVEAT: Metode ini hanya berfungsi jika dipanggil menggunakan referensi objek asli atau salinan yang tepat, seperti yang ditunjukkan dalam contoh. Namun, jika objek nullable dikotakkan ke Tipe lain (seperti objek, dll.) Alih-alih tetap dalam bentuk Nullable <> aslinya, metode ini tidak akan bekerja dengan andal. Jika kode yang memanggil metode ini tidak menggunakan referensi objek asli, tanpa kotak, atau salinan yang tepat, kode tersebut tidak dapat diandalkan untuk menentukan nullability objek menggunakan metode ini.
Dalam sebagian besar skenario pengkodean, untuk menentukan nullability, seseorang harus bergantung pada pengujian Jenis objek asli, bukan referensi (misalnya, kode harus memiliki akses ke Tipe asli objek untuk menentukan nullability). Dalam kasus yang lebih umum ini, IsTypeNullable (lihat tautan) adalah metode yang dapat diandalkan untuk menentukan nullability.
PS - Tentang "nullability"
Saya harus mengulangi pernyataan tentang pembatalan yang saya buat di pos terpisah, yang berlaku langsung untuk menangani topik ini dengan benar. Yaitu, saya percaya fokus pembahasan di sini seharusnya bukan bagaimana memeriksa untuk melihat apakah suatu objek adalah tipe Nullable generik, melainkan apakah seseorang dapat menetapkan nilai nol ke objek jenisnya. Dengan kata lain, saya pikir kita harus menentukan apakah tipe objek nullable, bukan apakah itu Nullable. Perbedaannya adalah dalam semantik, yaitu alasan praktis untuk menentukan nullability, yang biasanya adalah yang terpenting.
Dalam sistem yang menggunakan objek dengan tipe yang mungkin tidak diketahui hingga run-time (layanan web, panggilan jarak jauh, database, feed, dll.), Persyaratan umum adalah untuk menentukan apakah null dapat ditetapkan ke objek, atau apakah objek tersebut mungkin berisi sebuah nol. Melakukan operasi seperti itu pada tipe yang tidak dapat dibatalkan kemungkinan akan menghasilkan kesalahan, biasanya pengecualian, yang sangat mahal baik dalam hal kinerja dan persyaratan pengkodean. Untuk mengambil pendekatan yang sangat disukai untuk secara proaktif menghindari masalah seperti itu, perlu untuk menentukan apakah suatu objek dari Tipe arbitrer mampu mengandung null; yaitu, apakah secara umum 'nullable'.
Dalam arti yang sangat praktis dan khas, nullability dalam istilah .NET sama sekali tidak selalu menyiratkan bahwa Jenis objek adalah bentuk Nullable. Dalam banyak kasus pada kenyataannya, objek memiliki tipe referensi, dapat berisi nilai nol, dan dengan demikian semuanya dapat dibatalkan; tidak ada yang memiliki tipe Nullable. Oleh karena itu, untuk tujuan praktis dalam sebagian besar skenario, pengujian harus dilakukan untuk konsep umum nullability, vs konsep implementasi-tergantung Nullable. Jadi kita tidak boleh menutup telepon hanya dengan memfokuskan pada tipe .NET Nullable tetapi menggabungkan pemahaman kita tentang persyaratan dan perilakunya dalam proses pemfokusan pada konsep umum praktis tentang nullability.
sumber
Solusi paling sederhana yang saya buat adalah dengan mengimplementasikan solusi Microsoft ( Cara: Mengidentifikasi Jenis Nullable (C # Programming Guide) ) sebagai metode ekstensi:
Ini kemudian dapat disebut seperti ini:
Ini juga tampaknya cara yang logis untuk mengakses
IsNullable()
karena cocok dengan semuaIsXxxx()
metode lain diType
kelas.sumber
Hati-hati, saat meninju tipe nullable (
Nullable<int>
atau int? Misalnya):Itu menjadi tipe referensi yang benar, jadi Anda kehilangan fakta bahwa itu nullable.
sumber
Mungkin sedikit di luar topik, tetapi masih beberapa informasi menarik. Saya menemukan banyak orang yang menggunakan
Nullable.GetUnderlyingType() != null
identitas jika suatu tipe dapat dibatalkan. Ini jelas bekerja, tetapi Microsoft menyarankan berikut initype.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)
(lihat http://msdn.microsoft.com/en-us/library/ms366789.aspx ).Saya melihat ini dari sisi kinerja. Kesimpulan dari pengujian (satu juta upaya) di bawah ini adalah bahwa ketika suatu jenis nullable, opsi Microsoft memberikan kinerja terbaik.
Nullable.GetUnderlyingType (): 1335ms (3 kali lebih lambat)
GetGenericTypeDefinition () == typeof (Nullable <>): 500ms
Saya tahu bahwa kita berbicara tentang sejumlah kecil waktu, tetapi semua orang suka men-tweak milidetik :-)! Jadi jika Anda bos ingin Anda mengurangi beberapa milidetik maka ini adalah penyelamat Anda ...
sumber
Console.WriteLine
memang di luar area meteran;)Assert
harus berada di luar loop. Kedua, Anda juga harus mengujinya terhadap non-nullable juga untuk menguji kasus-kasus palsu. Saya melakukan tes yang sama (2 nulables dan 4 non-nullables) dan saya mendapatkan ~ 2 detik untukGetUnderlyingType
dan ~ 1 detik untukGetGenericTypeDefinition
, yaituGetGenericTypeDefinition
dua kali lebih cepat (bukan tiga kali).GetUnderlyingType
ini lebih lambat 2,5 kali. Dengan hanya non-nullables - kali ini keduanya leher dan leher.GetUnderlyingType
berguna ketika Anda harus memeriksa nullability & mendapatkan tipe yang mendasarinya jika itu nullable. Ini sangat berguna dan Anda sering melihat polaActivator.CreateInstance(Nullable.GetUnderlyingType(type) ?? type)
. Itu sepertias
kata kunci, memeriksa para pemeran serta melakukannya & mengembalikan hasil. Jika Anda ingin mendapatkan tipe nullable yang mendasarinya kembali maka melakukanGetGenericTypeDefinition
pemeriksaan dan kemudian mendapatkan tipe generik akan menjadi ide yang buruk. JugaGetUnderlyingType
jauh lebih mudah dibaca & berkesan. Saya tidak keberatan jika saya melakukannya hanya ~ 1000 kali.Versi ini:
:
sumber
Inilah yang saya pikirkan, karena segala sesuatu yang lain tampaknya gagal - setidaknya pada PLC - Portable Class Library / .NET Core dengan> = C # 6
Solusi: Perluas metode statis untuk Jenis apa pun
T
danNullable<T>
dan gunakan fakta bahwa metode ekstensi statis, yang cocok dengan jenis yang mendasarinya akan dipanggil dan diutamakan daripada generikT
ekstensi .Untuk
T
:dan untuk
Nullable<T>
Menggunakan Refleksi dan
type.IsGenericType
... tidak berfungsi pada rangkaian .NET Runtimes saya saat ini. Dokumentasi MSDN juga tidak membantu.if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {…}
Sebagian karena API Refleksi telah diubah cukup signifikan dalam .NET Core.
sumber
Saya pikir yang menggunakan pengujian yang disarankan Microsoft
IsGenericType
bagus, tetapi dalam kode untukGetUnderlyingType
, Microsoft menggunakan tes tambahan untuk memastikan Anda tidak lulus dalam definisi tipe umumNullable<>
:sumber
cara sederhana untuk melakukan ini:
ini adalah unit test saya dan semuanya lulus
tes unit aktual
sumber