2009-11-17 33 views
73

Có cách nào để xác định có hay không. Loại Net là một số? Ví dụ: System.UInt32/UInt16/Double là tất cả các số. Tôi muốn tránh trường hợp chuyển đổi dài trên Type.FullName.C# - cách xác định Loại có phải là số

+4

Dupe của nhiều người, nhiều, rất nhiều. Tại sao điều này chưa được đóng? – Noldorin

+2

Bản sao của http://stackoverflow.com/questions/1130698/ và rất gần với một số người khác. –

+0

có thể trùng lặp của [Sử dụng .Net, làm thế nào tôi có thể xác định xem một loại có phải là một loại giá trị số không?] (Http: // stackoverflow.com/questions/124411/using-net-how-can-i-defined-if-a-type-là-a-số-valuetype) – nawfal

Trả lời

77

Hãy thử điều này:

Type type = object.GetType(); 
bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char)); 

Các loại nguyên thủy là Boolean, Byte, SByte, Int16, uint16, Int32, UInt32, Int64, UInt64, Char, đôi, và Độc.

Lấy Guillaume's solution xa hơn một chút:

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; 
    } 
} 

Cách sử dụng:

int i = 32; 
i.IsNumericType(); // True 

string s = "Hello World"; 
s.IsNumericType(); // False 
+2

Vì vậy, loại 'thập phân' không phải là số? – LukeH

+0

Các kiểu nguyên thủy là Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double và Single. –

+0

@Luke - câu hỏi hay. Đó là một cấu trúc - vì vậy bạn cần xác định số. –

2

Bạn có thể sử dụng Type.IsPrimitive và sau đó phân loại ra các BooleanChar loại, một cái gì đó như thế này:

bool IsNumeric(Type type) 
{ 
    return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool); 
} 

EDIT: Bạn có thể muốn loại trừ IntPtrUIntPtr loại là tốt, nếu bạn don' t coi chúng là số.

+0

Tôi biết, tôi đã cập nhật câu trả lời trong khi bạn đang nhận xét. – Konamiman

+1

Vì vậy, loại 'thập phân' không phải là số? – LukeH

+0

Rất tiếc ... có vẻ như giải pháp của Guillaume là tốt nhất. – Konamiman

0

Rất tiếc, các loại này không có nhiều điểm chung, trừ các loại giá trị. Nhưng để tránh trường hợp chuyển đổi dài, bạn chỉ có thể xác định danh sách chỉ đọc với tất cả các loại này và sau đó chỉ cần kiểm tra xem loại đã cho có nằm trong danh sách hay không.

69

Không sử dụng một công tắc - chỉ cần sử dụng một bộ:

HashSet<Type> NumericTypes = new HashSet<Type> 
{ 
    typeof(decimal), typeof(byte), typeof(sbyte), 
    typeof(short), typeof(ushort), ... 
}; 

EDIT: Một lợi thế của việc này qua sử dụng một mã loại là khi loại số mới được đưa vào NET (ví dụ BigIntegerComplex) dễ điều chỉnh - trong khi các loại đó sẽ không nhận mã loại.

+3

và cách bạn sử dụng HashSet? – RvdK

+7

NumericTypes.Contains (bất cứ điều gì)? – mquander

+2

bool isANumber = NumericTypes.Contains (classInstance.GetType()); –

1

Câu trả lời ngắn: Số

Câu trả lời dài hơn: Không.

Thực tế là nhiều loại khác nhau trong C# có thể chứa dữ liệu số. Trừ khi bạn biết những gì mong đợi (Int, Double, vv), bạn cần phải sử dụng câu lệnh "long".

0

oops! Đã hiểu sai câu hỏi! Cá nhân, sẽ cuộn với Skeet's.


HRM, âm thanh như bạn muốn DoSomething trên Type dữ liệu của bạn. Những gì bạn có thể làm là:

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; 
    } 
} 
1

Đây là tất cả các loại giá trị (ngoại trừ bool và có thể enum).Vì vậy, bạn chỉ đơn giản là có thể sử dụng:

bool IsNumberic(object o) 
{ 
    return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum)) 
} 
+1

Điều này sẽ trả về true cho bất kỳ 'struct' do người dùng định nghĩa ... Tôi không nghĩ đó là điều bạn muốn. –

+1

Bạn đã đúng. Các kiểu số tích hợp cũng là cấu trúc. Vì vậy, tốt hơn đi với so sánh nguyên thủy sau đó. – MandoMando

28
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; 
    } 
} 

Lưu ý về tối ưu hóa loại bỏ (xem ý kiến ​​enzi) Và nếu bạn thực sự muốn tối ưu hóa nó (mất khả năng đọc và một số an toàn ...):

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; 
} 

+12

Tôi biết câu trả lời này là cũ, nhưng gần đây tôi đã đi qua một chuyển đổi như vậy: không sử dụng tối ưu hóa được đề xuất! Tôi nhìn vào mã IL được tạo ra từ một công tắc như vậy, và lưu ý rằng trình biên dịch đã áp dụng tối ưu hóa (trong IL 5 được trừ khỏi mã loại và sau đó các giá trị từ 0 đến 10 được coi là đúng). Do đó việc chuyển đổi nên được sử dụng cho nó dễ đọc hơn và an toàn hơn và cũng nhanh như vậy. – enzi

+0

Nếu bạn thực sự muốn tối ưu hóa nó và không quan tâm đến khả năng đọc thì mã tối ưu sẽ là 'return unchecked ((uint) Type.GetTypeCode (type) - 5u) <= 10u;' do đó loại bỏ nhánh được giới thiệu bởi '&&' . – AnorZaken

49

Không ai trong số các giải pháp cần Nul lable vào tài khoản.

tôi sửa đổi giải pháp Jon Skeet một chút:

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)); 
    } 

Tôi biết tôi chỉ có thể thêm nullables bản thân để HashSet tôi. Nhưng giải pháp này tránh được nguy cơ quên thêm một Nullable cụ thể vào danh sách của bạn.

private static HashSet<Type> NumericTypes = new HashSet<Type> 
    { 
     typeof(int), 
     typeof(int?), 
     ... 
    }; 
+1

Là một loại nullable thực sự là số? Null không phải là một con số, theo hiểu biết của tôi. – IllidanS4

+0

Điều đó phụ thuộc vào những gì bạn muốn đạt được. Trong trường hợp của tôi, tôi cũng cần bao gồm cả null. Nhưng tôi cũng có thể nghĩ về những tình huống mà đây không phải là hành vi mong muốn. –

8

Cách tiếp cận dựa trên Philip's proposal, tăng cường với SFun28's inner type check cho Nullable loại:

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; 
     } 
    } 
} 

Tại sao điều này? Tôi phải kiểm tra xem một số Type type có phải là một loại số không, và không nếu một số object o tùy ý là số.

8

Về cơ bản giải pháp Skeet nhưng bạn có thể tái sử dụng nó với các loại Nullable như sau:

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); 
    } 
} 
1

Điều này có thể làm việc tốt. Tuy nhiên, bạn có thể muốn theo dõi nó bằng Type.Parse để truyền theo cách bạn muốn sau đó.

public bool IsNumeric(object value) 
{ 
    float testValue; 
    return float.TryParse(value.ToString(), out testValue); 
} 
0

Modified của Skeet và giải pháp arviman của sử dụng Generics, Reflection, và 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) 
}; 

Tiếp theo bởi:

public static bool IsNumeric<T>(this T myType) 
{ 
    var IsNumeric = false; 

    if(myType != null) 
    { 
     IsNumeric = m_numTypes.Contains(myType.GetType()); 
    } 

    return IsNumeric; 
} 

Cách sử dụng cho (T item):

if (item.IsNumeric()) {} 

null lợi nhuận sai.

0

Với C# 7 phương pháp này mang lại cho tôi hiệu suất tốt hơn so với trường hợp chuyển đổi trên TypeCodeHashSet<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; 

thử nghiệm đang theo dõi:

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); 
    } 
Các vấn đề liên quan