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.
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.
Jawaban:
Coba ini:
Type type = object.GetType();
bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char));
Jenis primitif adalah Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Char, Double, dan Single.
Mengambil solusi Guillaume sedikit lebih jauh:
public static bool IsNumericType(this object o)
{
switch (Type.GetTypeCode(o.GetType()))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
Pemakaian:
int i = 32;
i.IsNumericType(); // True
string s = "Hello World";
s.IsNumericType(); // False
decimaljenisnya 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:
HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(decimal), typeof(byte), typeof(sbyte),
typeof(short), typeof(ushort), ...
};
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.
switchtidak berhasil Type, jadi Anda tidak bisa. Anda TypeCodetentu saja dapat mengaktifkannya , tetapi itu masalah lain.
Tidak ada solusi yang memperhitungkan Nullable.
Saya sedikit memodifikasi solusi Jon Skeet:
private static HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int),
typeof(uint),
typeof(double),
typeof(decimal),
...
};
internal static bool IsNumericType(Type type)
{
return NumericTypes.Contains(type) ||
NumericTypes.Contains(Nullable.GetUnderlyingType(type));
}
Saya tahu saya bisa menambahkan nullables itu sendiri ke HashSet saya. Tetapi solusi ini menghindari bahaya lupa menambahkan Nullable tertentu ke daftar Anda.
private static HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int),
typeof(int?),
...
};
public static bool IsNumericType(Type type)
{
switch (Type.GetTypeCode(type))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
Catatan tentang pengoptimalan dihapus (lihat komentar enzi)
Dan jika Anda benar-benar ingin mengoptimalkannya (kehilangan keterbacaan dan keamanan ...):
public static bool IsNumericType(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;
}
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:
public static class TypeHelper
{
private static readonly HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int), typeof(double), typeof(decimal),
typeof(long), typeof(short), typeof(sbyte),
typeof(byte), typeof(ulong), typeof(ushort),
typeof(uint), typeof(float)
};
public static bool IsNumeric(Type myType)
{
return NumericTypes.Contains(Nullable.GetUnderlyingType(myType) ?? myType);
}
}
Pendekatan berdasarkan proposal Philip , ditingkatkan dengan pemeriksaan tipe dalam SFun28 untuk Nullabletipe:
public static class IsNumericType
{
public static bool IsNumeric(this Type type)
{
switch (Type.GetTypeCode(type))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
case TypeCode.Object:
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return Nullable.GetUnderlyingType(type).IsNumeric();
//return IsNumeric(Nullable.GetUnderlyingType(type));
}
return false;
default:
return false;
}
}
}
Kenapa ini? Saya harus memeriksa apakah yang diberikan Type typeadalah tipe numerik, dan bukan jika sembarang object oadalah numerik.
Dengan C # 7, metode ini memberi saya kinerja yang lebih baik daripada kasus sakelar TypeCodedan HashSet<Type>:
public static bool IsNumeric(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is float || o is double || o is decimal;
Tesnya adalah sebagai berikut:
public static class Extensions
{
public static HashSet<Type> NumericTypes = new HashSet<Type>()
{
typeof(byte), typeof(sbyte), typeof(ushort), typeof(uint), typeof(ulong), typeof(short), typeof(int), typeof(long), typeof(decimal), typeof(double), typeof(float)
};
public static bool IsNumeric1(this object o) => NumericTypes.Contains(o.GetType());
public static bool IsNumeric2(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is decimal || o is double || o is float;
public static bool IsNumeric3(this object o)
{
switch (o)
{
case Byte b:
case SByte sb:
case UInt16 u16:
case UInt32 u32:
case UInt64 u64:
case Int16 i16:
case Int32 i32:
case Int64 i64:
case Decimal m:
case Double d:
case Single f:
return true;
default:
return false;
}
}
public static bool IsNumeric4(this object o)
{
switch (Type.GetTypeCode(o.GetType()))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
}
class Program
{
static void Main(string[] args)
{
var count = 100000000;
//warm up calls
for (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 here
var sw = new Stopwatch();
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);
}
Anda dapat menggunakan Type.IsPrimitive dan kemudian mengurutkan Booleandan Chartype, seperti ini:
bool IsNumeric(Type type)
{
return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool);
}
EDIT : Anda mungkin ingin mengecualikan IntPtrdan UIntPtrjenis juga, jika Anda tidak menganggapnya sebagai numerik.
decimaljenisnya bukan numerik?
Ketik ekstensi dengan dukungan tipe null.
public static bool IsNumeric(this Type type)
{
if (type == null) { return false; }
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
type = type.GetGenericArguments()[0];
}
switch (Type.GetTypeCode(type))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
Dimodifikasi skeet dan solusi arviman ini memanfaatkan Generics, Reflectiondan C# v6.0.
private static readonly HashSet<Type> m_numTypes = new HashSet<Type>
{
typeof(int), typeof(double), typeof(decimal),
typeof(long), typeof(short), typeof(sbyte),
typeof(byte), typeof(ulong), typeof(ushort),
typeof(uint), typeof(float), typeof(BigInteger)
};
Diikuti oleh:
public static bool IsNumeric<T>( this T myType )
{
var IsNumeric = false;
if( myType != null )
{
IsNumeric = m_numTypes.Contains( myType.GetType() );
}
return IsNumeric;
}
Penggunaan untuk (T item):
if ( item.IsNumeric() ) {}
null mengembalikan salah.
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):
public static class TypeExtensions
{
private static readonly HashSet<Type> NumberTypes = new HashSet<Type>();
static TypeExtensions()
{
NumberTypes.Add(typeof(byte));
NumberTypes.Add(typeof(decimal));
NumberTypes.Add(typeof(double));
NumberTypes.Add(typeof(float));
NumberTypes.Add(typeof(int));
NumberTypes.Add(typeof(long));
NumberTypes.Add(typeof(sbyte));
NumberTypes.Add(typeof(short));
NumberTypes.Add(typeof(uint));
NumberTypes.Add(typeof(ulong));
NumberTypes.Add(typeof(ushort));
}
public static bool IsNumber(this Type type)
{
return NumberTypes.Contains(type);
}
}
Coba paket nuget TypeSupport untuk C #. Ini memiliki dukungan untuk mendeteksi semua tipe numerik (di antara banyak fitur lainnya):
var extendedType = typeof(int).GetExtendedType();
Assert.IsTrue(extendedType.IsNumericType);
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.
Mereka semua adalah tipe nilai (kecuali untuk bool dan mungkin enum). Jadi Anda cukup menggunakan:
bool IsNumberic(object o)
{
return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum))
}
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:
public static bool IsNumericType(this object o)
{
var t = (byte)Convert.GetTypeCode(o);
return t > 4 && t < 16;
}
Diberikan definisi enum berikut untuk TypeCode:
public enum TypeCode
{
Empty = 0,
Object = 1,
DBNull = 2,
Boolean = 3,
Char = 4,
SByte = 5,
Byte = 6,
Int16 = 7,
UInt16 = 8,
Int32 = 9,
UInt32 = 10,
Int64 = 11,
UInt64 = 12,
Single = 13,
Double = 14,
Decimal = 15,
DateTime = 16,
String = 18
}
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
public class MyClass
{
private readonly Dictionary<Type, Func<SomeResult, object>> _map =
new Dictionary<Type, Func<SomeResult, object>> ();
public MyClass ()
{
_map.Add (typeof (int), o => return SomeTypeSafeMethod ((int)(o)));
}
public SomeResult DoSomething<T>(T numericValue)
{
Type valueType = typeof (T);
if (!_map.Contains (valueType))
{
throw new NotSupportedException (
string.Format (
"Does not support Type [{0}].", valueType.Name));
}
SomeResult result = _map[valueType] (numericValue);
return result;
}
}