Apakah ada cara untuk menentukan apakah Jenis Net yang diberikan adalah angka atau tidak? Misalnya: System.UInt32/UInt16/Doublesemua angka. Saya ingin menghindari sakelar panjang di Type.FullName.
@Xaero: Saya tidak ragu bahwa decimaladalah numerik. Hanya karena ini bukan primitif tidak berarti itu bukan numerik. Kode Anda perlu memperhitungkan ini.
LukeH
2
Ini perlu direkayasa ulang untuk tipe numerik baru di .NET 4.0 yang tidak memiliki kode tipe.
Jon Skeet
7
Bagaimana Anda bisa memberi saya suara rendah pada jawaban berdasarkan teknologi saat ini. Mungkin di .NET 62, int akan dihapus - apakah Anda akan merendahkan semua jawaban dengan int?
Philip Wallace
1
@DiskJunky Maaf, teman. Itu hampir tiga tahun lalu dan saya tidak ingat apa isinya.
EDIT: Satu keuntungan dari ini dibandingkan menggunakan kode tipe adalah bahwa ketika tipe numerik baru diperkenalkan ke NET (misalnya BigInteger dan Kompleks ) mudah untuk menyesuaikan - sedangkan tipe tersebut tidak akan mendapatkan kode tipe.
Saya tahu saya bisa menambahkan nullables itu sendiri ke HashSet saya. Tetapi solusi ini menghindari bahaya lupa menambahkan Nullable tertentu ke daftar Anda.
Apakah tipe nullable benar-benar numerik? Null bukanlah angka, setahu saya.
IllidanS4 ingin Monica kembali
2
Itu tergantung pada apa yang ingin Anda capai. Dalam kasus saya, saya perlu menyertakan nullables juga. Tetapi saya juga dapat memikirkan situasi di mana ini bukan perilaku yang diinginkan.
Jürgen Steinblock
Baik! Untuk memperlakukan angka nullable sebagai angka sangat berguna dalam validasi input UI.
guogangj
1
@ IllidanS4 Ceknya ada di Type bukan nilainya. Dalam kebanyakan kasus, tipe numerik Nullable harus diperlakukan sebagai numerik. Tentu saja jika cek itu pada nilai dan nilainya null, maka ya itu tidak boleh dianggap numerik.
Catatan tentang pengoptimalan dihapus (lihat komentar enzi)
Dan jika Anda benar-benar ingin mengoptimalkannya (kehilangan keterbacaan dan keamanan ...):
publicstaticboolIsNumericType(Type type){TypeCode typeCode =Type.GetTypeCode(type);//The TypeCode of numerical types are between SByte (5) and Decimal (15).return(int)typeCode >=5&&(int)typeCode <=15;}
Saya tahu jawaban ini sudah lama, tetapi saya baru-baru ini menemukan peralihan seperti itu: jangan gunakan pengoptimalan yang disarankan! Saya melihat kode IL yang dihasilkan dari sakelar semacam itu, dan mencatat bahwa kompiler sudah menerapkan pengoptimalan (di IL 5 dikurangi dari kode jenis dan kemudian nilai dari 0 hingga 10 dianggap benar). Oleh karena itu, sakelar harus digunakan agar lebih mudah dibaca dan lebih aman serta sama cepatnya.
enzi
1
Jika Anda benar-benar ingin mengoptimalkannya dan tidak peduli tentang keterbacaan, kode yang optimal akan return unchecked((uint)Type.GetTypeCode(type) - 5u) <= 10u;menghapus cabang yang diperkenalkan oleh &&.
AnorZaken
14
Pada dasarnya solusi Skeet tetapi Anda dapat menggunakannya kembali dengan tipe Nullable sebagai berikut:
Dengan C # 7, metode ini memberi saya kinerja yang lebih baik daripada kasus sakelar TypeCodedan HashSet<Type>:
publicstaticboolIsNumeric(thisobject o)=> o isbyte|| o issbyte|| o isushort|| o isuint|| o isulong|| o isshort|| o isint|| o islong|| o isfloat|| o isdouble|| o isdecimal;
Tesnya adalah sebagai berikut:
publicstaticclassExtensions{publicstaticHashSet<Type>NumericTypes=newHashSet<Type>(){typeof(byte),typeof(sbyte),typeof(ushort),typeof(uint),typeof(ulong),typeof(short),typeof(int),typeof(long),typeof(decimal),typeof(double),typeof(float)};publicstaticboolIsNumeric1(thisobject o)=>NumericTypes.Contains(o.GetType());publicstaticboolIsNumeric2(thisobject o)=> o isbyte|| o issbyte|| o isushort|| o isuint|| o isulong|| o isshort|| o isint|| o islong|| o isdecimal|| o isdouble|| o isfloat;publicstaticboolIsNumeric3(thisobject o){switch(o){caseByte b:caseSByte sb:caseUInt16 u16:caseUInt32 u32:caseUInt64 u64:caseInt16 i16:caseInt32 i32:caseInt64 i64:caseDecimal m:caseDouble d:caseSingle f:returntrue;default:returnfalse;}}publicstaticboolIsNumeric4(thisobject o){switch(Type.GetTypeCode(o.GetType())){caseTypeCode.Byte:caseTypeCode.SByte:caseTypeCode.UInt16:caseTypeCode.UInt32:caseTypeCode.UInt64:caseTypeCode.Int16:caseTypeCode.Int32:caseTypeCode.Int64:caseTypeCode.Decimal:caseTypeCode.Double:caseTypeCode.Single:returntrue;default:returnfalse;}}}classProgram{staticvoidMain(string[] args){var count =100000000;//warm up callsfor(var i =0; i < count; i++){
i.IsNumeric1();}for(var i =0; i < count; i++){
i.IsNumeric2();}for(var i =0; i < count; i++){
i.IsNumeric3();}for(var i =0; i < count; i++){
i.IsNumeric4();}//Tests begin herevar sw =newStopwatch();
sw.Restart();for(var i =0; i < count; i++){
i.IsNumeric1();}
sw.Stop();Debug.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();for(var i =0; i < count; i++){
i.IsNumeric2();}
sw.Stop();Debug.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();for(var i =0; i < count; i++){
i.IsNumeric3();}
sw.Stop();Debug.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();for(var i =0; i < count; i++){
i.IsNumeric4();}
sw.Stop();Debug.WriteLine(sw.ElapsedMilliseconds);}
Faktanya adalah bahwa banyak tipe berbeda dalam C # dapat berisi data numerik. Kecuali Anda tahu apa yang diharapkan (Int, Double, dll), Anda perlu menggunakan pernyataan case "long".
Switch agak lambat, karena setiap kali metode dalam situasi terburuk akan melalui semua jenis. Menurut saya, menggunakan Dictonary lebih bagus, dalam situasi ini Anda akan mendapatkan O(1):
Saya tidak tahu paket ini. Tampaknya menjadi penyelamat dalam banyak kasus untuk menghindari menulis kode kami sendiri untuk jenis operasi yang diminta oleh OP. Terima kasih!
AFakt
0
Sayangnya tipe ini tidak memiliki banyak kesamaan selain mereka semua tipe nilai. Tetapi untuk menghindari kasus-peralihan yang panjang Anda bisa mendefinisikan daftar hanya-baca dengan semua tipe ini dan kemudian hanya memeriksa apakah tipe yang diberikan ada di dalam daftar.
Ini akan mengembalikan true untuk setiap yang ditentukan pengguna struct... Saya tidak berpikir itu yang Anda inginkan.
Dan Tao
1
Anda benar. Tipe numerik built-in adalah struct juga. Jadi lebih baik gunakan perbandingan Primitif.
MandoMando
0
EDIT: Ya, saya memodifikasi kode di bawah ini menjadi lebih berkinerja dan kemudian menjalankan tes yang diposting oleh @Hugo terhadapnya. Kecepatannya hampir setara dengan IF @Hugo menggunakan item terakhir dalam urutannya (Desimal). Namun jika menggunakan item pertama 'byte' nya mengambil kue, tetapi jelas urutan penting dalam hal kinerja. Meskipun menggunakan kode di bawah ini lebih mudah untuk ditulis dan lebih konsisten pada biayanya, bagaimanapun, itu tidak dapat dipelihara atau dapat dibuktikan di masa depan.
Sepertinya beralih dari Type.GetTypeCode () ke Convert.GetTypeCode () mempercepat kinerja secara drastis, sekitar 25%, VS Enum.Parse () yang 10 kali lebih lambat.
Saya tahu posting ini sudah tua tetapi JIKA menggunakan metode enum TypeCode, termudah (dan mungkin yang termurah) akan menjadi seperti ini:
publicstaticboolIsNumericType(thisobject o){var t =(byte)Convert.GetTypeCode(o);return t >4&& t <16;}
Saya belum mengujinya secara menyeluruh, tetapi untuk tipe numerik C # dasar, ini sepertinya menutupinya. Namun, seperti yang disebutkan @JonSkeet, enum ini tidak diperbarui untuk jenis tambahan yang ditambahkan ke .NET di masa mendatang.
Ups! Salah membaca pertanyaan! Secara pribadi, akan berguling dengan Skeet's .
hrm, suara seperti Anda ingin DoSomethingpada Typedata Anda. Apa yang dapat Anda lakukan adalah sebagai berikut
publicclassMyClass{privatereadonlyDictionary<Type,Func<SomeResult,object>> _map =newDictionary<Type,Func<SomeResult,object>>();publicMyClass(){
_map.Add(typeof(int), o =>returnSomeTypeSafeMethod((int)(o)));}publicSomeResultDoSomething<T>(T numericValue){Type valueType =typeof(T);if(!_map.Contains(valueType)){thrownewNotSupportedException(string.Format("Does not support Type [{0}].", valueType.Name));}SomeResult result = _map[valueType](numericValue);return result;}}
Jawaban:
Coba ini:Mengambil solusi Guillaume sedikit lebih jauh:
Pemakaian:
sumber
decimal
jenisnya bukan numerik?decimal
adalah numerik. Hanya karena ini bukan primitif tidak berarti itu bukan numerik. Kode Anda perlu memperhitungkan ini.Jangan gunakan sakelar - cukup gunakan satu set:
EDIT: Satu keuntungan dari ini dibandingkan menggunakan kode tipe adalah bahwa ketika tipe numerik baru diperkenalkan ke NET (misalnya BigInteger dan Kompleks ) mudah untuk menyesuaikan - sedangkan tipe tersebut tidak akan mendapatkan kode tipe.
sumber
switch
tidak berhasilType
, jadi Anda tidak bisa. AndaTypeCode
tentu saja dapat mengaktifkannya , tetapi itu masalah lain.Tidak ada solusi yang memperhitungkan Nullable.
Saya sedikit memodifikasi solusi Jon Skeet:
Saya tahu saya bisa menambahkan nullables itu sendiri ke HashSet saya. Tetapi solusi ini menghindari bahaya lupa menambahkan Nullable tertentu ke daftar Anda.
sumber
Catatan tentang pengoptimalan dihapus (lihat komentar enzi)
Dan jika Anda benar-benar ingin mengoptimalkannya (kehilangan keterbacaan dan keamanan ...):sumber
return unchecked((uint)Type.GetTypeCode(type) - 5u) <= 10u;
menghapus cabang yang diperkenalkan oleh&&
.Pada dasarnya solusi Skeet tetapi Anda dapat menggunakannya kembali dengan tipe Nullable sebagai berikut:
sumber
Pendekatan berdasarkan proposal Philip , ditingkatkan dengan pemeriksaan tipe dalam SFun28 untuk
Nullable
tipe:Kenapa ini? Saya harus memeriksa apakah yang diberikan
Type type
adalah tipe numerik, dan bukan jika sembarangobject o
adalah numerik.sumber
Dengan C # 7, metode ini memberi saya kinerja yang lebih baik daripada kasus sakelar
TypeCode
danHashSet<Type>
:Tesnya adalah sebagai berikut:
sumber
Anda dapat menggunakan Type.IsPrimitive dan kemudian mengurutkan
Boolean
danChar
type, seperti ini:EDIT : Anda mungkin ingin mengecualikan
IntPtr
danUIntPtr
jenis juga, jika Anda tidak menganggapnya sebagai numerik.sumber
decimal
jenisnya bukan numerik?Ketik ekstensi dengan dukungan tipe null.
sumber
Jawaban singkatnya: Tidak.
Jawaban yang Lebih Panjang: Tidak.
Faktanya adalah bahwa banyak tipe berbeda dalam C # dapat berisi data numerik. Kecuali Anda tahu apa yang diharapkan (Int, Double, dll), Anda perlu menggunakan pernyataan case "long".
sumber
Ini mungkin berhasil juga. Namun, Anda mungkin ingin menindaklanjutinya dengan Type.Parse untuk mentransmisikannya sesuai keinginan Anda sesudahnya.
sumber
Dimodifikasi skeet dan solusi arviman ini memanfaatkan
Generics
,Reflection
danC# v6.0
.Diikuti oleh:
Penggunaan untuk
(T item)
:null
mengembalikan salah.sumber
Switch agak lambat, karena setiap kali metode dalam situasi terburuk akan melalui semua jenis. Menurut saya, menggunakan Dictonary lebih bagus, dalam situasi ini Anda akan mendapatkan
O(1)
:sumber
Coba paket nuget TypeSupport untuk C #. Ini memiliki dukungan untuk mendeteksi semua tipe numerik (di antara banyak fitur lainnya):
sumber
Sayangnya tipe ini tidak memiliki banyak kesamaan selain mereka semua tipe nilai. Tetapi untuk menghindari kasus-peralihan yang panjang Anda bisa mendefinisikan daftar hanya-baca dengan semua tipe ini dan kemudian hanya memeriksa apakah tipe yang diberikan ada di dalam daftar.
sumber
Mereka semua adalah tipe nilai (kecuali untuk bool dan mungkin enum). Jadi Anda cukup menggunakan:
sumber
struct
... Saya tidak berpikir itu yang Anda inginkan.EDIT: Ya, saya memodifikasi kode di bawah ini menjadi lebih berkinerja dan kemudian menjalankan tes yang diposting oleh @Hugo terhadapnya. Kecepatannya hampir setara dengan IF @Hugo menggunakan item terakhir dalam urutannya (Desimal). Namun jika menggunakan item pertama 'byte' nya mengambil kue, tetapi jelas urutan penting dalam hal kinerja. Meskipun menggunakan kode di bawah ini lebih mudah untuk ditulis dan lebih konsisten pada biayanya, bagaimanapun, itu tidak dapat dipelihara atau dapat dibuktikan di masa depan.
Sepertinya beralih dari Type.GetTypeCode () ke Convert.GetTypeCode () mempercepat kinerja secara drastis, sekitar 25%, VS Enum.Parse () yang 10 kali lebih lambat.
Saya tahu posting ini sudah tua tetapi JIKA menggunakan metode enum TypeCode, termudah (dan mungkin yang termurah) akan menjadi seperti ini:
Diberikan definisi enum berikut untuk TypeCode:
Saya belum mengujinya secara menyeluruh, tetapi untuk tipe numerik C # dasar, ini sepertinya menutupinya. Namun, seperti yang disebutkan @JonSkeet, enum ini tidak diperbarui untuk jenis tambahan yang ditambahkan ke .NET di masa mendatang.
sumber
Ups! Salah membaca pertanyaan! Secara pribadi, akan berguling dengan Skeet's .
hrm, suara seperti Anda ingin
DoSomething
padaType
data Anda. Apa yang dapat Anda lakukan adalah sebagai berikutsumber