Использование .Net, как я могу определить, является ли тип числовым типом значений?

#c# #reflection #.net-4.5

#.net #отражение

Вопрос:

Но вот пример:

 Dim desiredType as Type
if IsNumeric(desiredType) then ...
  

РЕДАКТИРОВАТЬ: я знаю только тип, а не значение в виде строки.

Хорошо, к сожалению, мне приходится перебирать код типа.

Но это хороший способ сделать это:

  if ((desiredType.IsArray))
      return 0;

 switch (Type.GetTypeCode(desiredType))
 {
      case 3:
      case 6:
      case 7:
      case 9:
      case 11:
      case 13:
      case 14:
      case 15:
          return 1;
 }
 ;return 0;
  

Комментарии:

1. Здесь несколько лет спустя, но почему isArray имеет значение? Массив является объектом и должен отказать вашему коммутатору.

Ответ №1:

С опозданием на несколько лет, но вот мое решение (вы можете выбрать, включать ли логическое значение). Решает для случая с нулевым значением. Включен тест xUnit

 /// <summary>
/// Determines if a type is numeric.  Nullable numeric types are considered numeric.
/// </summary>
/// <remarks>
/// Boolean is not considered numeric.
/// </remarks>
public static bool IsNumericType( Type type )
{
    if (type == null)
    {
        return false;
    }

    switch (Type.GetTypeCode(type))
    {
        case TypeCode.Byte:
        case TypeCode.Decimal:
        case TypeCode.Double:
        case TypeCode.Int16:
        case TypeCode.Int32:
        case TypeCode.Int64:
        case TypeCode.SByte:
        case TypeCode.Single:
        case TypeCode.UInt16:
        case TypeCode.UInt32:
        case TypeCode.UInt64:
            return true;
        case TypeCode.Object:
            if ( type.IsGenericType amp;amp; type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
               return IsNumericType(Nullable.GetUnderlyingType(type));
            }
            return false;
    }
    return false;
}



/// <summary>
/// Tests the IsNumericType method.
/// </summary>
[Fact]
public void IsNumericTypeTest()
{
    // Non-numeric types
    Assert.False(TypeHelper.IsNumericType(null));
    Assert.False(TypeHelper.IsNumericType(typeof(object)));
    Assert.False(TypeHelper.IsNumericType(typeof(DBNull)));
    Assert.False(TypeHelper.IsNumericType(typeof(bool)));
    Assert.False(TypeHelper.IsNumericType(typeof(char)));
    Assert.False(TypeHelper.IsNumericType(typeof(DateTime)));
    Assert.False(TypeHelper.IsNumericType(typeof(string)));

    // Arrays of numeric and non-numeric types
    Assert.False(TypeHelper.IsNumericType(typeof(object[])));
    Assert.False(TypeHelper.IsNumericType(typeof(DBNull[])));
    Assert.False(TypeHelper.IsNumericType(typeof(bool[])));
    Assert.False(TypeHelper.IsNumericType(typeof(char[])));
    Assert.False(TypeHelper.IsNumericType(typeof(DateTime[])));
    Assert.False(TypeHelper.IsNumericType(typeof(string[])));
    Assert.False(TypeHelper.IsNumericType(typeof(byte[])));
    Assert.False(TypeHelper.IsNumericType(typeof(decimal[])));
    Assert.False(TypeHelper.IsNumericType(typeof(double[])));
    Assert.False(TypeHelper.IsNumericType(typeof(short[])));
    Assert.False(TypeHelper.IsNumericType(typeof(int[])));
    Assert.False(TypeHelper.IsNumericType(typeof(long[])));
    Assert.False(TypeHelper.IsNumericType(typeof(sbyte[])));
    Assert.False(TypeHelper.IsNumericType(typeof(float[])));
    Assert.False(TypeHelper.IsNumericType(typeof(ushort[])));
    Assert.False(TypeHelper.IsNumericType(typeof(uint[])));
    Assert.False(TypeHelper.IsNumericType(typeof(ulong[])));

    // numeric types
    Assert.True(TypeHelper.IsNumericType(typeof(byte)));
    Assert.True(TypeHelper.IsNumericType(typeof(decimal)));
    Assert.True(TypeHelper.IsNumericType(typeof(double)));
    Assert.True(TypeHelper.IsNumericType(typeof(short)));
    Assert.True(TypeHelper.IsNumericType(typeof(int)));
    Assert.True(TypeHelper.IsNumericType(typeof(long)));
    Assert.True(TypeHelper.IsNumericType(typeof(sbyte)));
    Assert.True(TypeHelper.IsNumericType(typeof(float)));
    Assert.True(TypeHelper.IsNumericType(typeof(ushort)));
    Assert.True(TypeHelper.IsNumericType(typeof(uint)));
    Assert.True(TypeHelper.IsNumericType(typeof(ulong)));

    // Nullable non-numeric types
    Assert.False(TypeHelper.IsNumericType(typeof(bool?)));
    Assert.False(TypeHelper.IsNumericType(typeof(char?)));
    Assert.False(TypeHelper.IsNumericType(typeof(DateTime?)));

    // Nullable numeric types
    Assert.True(TypeHelper.IsNumericType(typeof(byte?)));
    Assert.True(TypeHelper.IsNumericType(typeof(decimal?)));
    Assert.True(TypeHelper.IsNumericType(typeof(double?)));
    Assert.True(TypeHelper.IsNumericType(typeof(short?)));
    Assert.True(TypeHelper.IsNumericType(typeof(int?)));
    Assert.True(TypeHelper.IsNumericType(typeof(long?)));
    Assert.True(TypeHelper.IsNumericType(typeof(sbyte?)));
    Assert.True(TypeHelper.IsNumericType(typeof(float?)));
    Assert.True(TypeHelper.IsNumericType(typeof(ushort?)));
    Assert.True(TypeHelper.IsNumericType(typeof(uint?)));
    Assert.True(TypeHelper.IsNumericType(typeof(ulong?)));

    // Testing with GetType because of handling with non-numerics. See:
    // http://msdn.microsoft.com/en-us/library/ms366789.aspx

    // Using GetType - non-numeric
    Assert.False(TypeHelper.IsNumericType((new object()).GetType()));
    Assert.False(TypeHelper.IsNumericType(DBNull.Value.GetType()));
    Assert.False(TypeHelper.IsNumericType(true.GetType()));
    Assert.False(TypeHelper.IsNumericType('a'.GetType()));
    Assert.False(TypeHelper.IsNumericType((new DateTime(2009, 1, 1)).GetType()));
    Assert.False(TypeHelper.IsNumericType(string.Empty.GetType()));

    // Using GetType - numeric types
    // ReSharper disable RedundantCast
    Assert.True(TypeHelper.IsNumericType((new byte()).GetType()));
    Assert.True(TypeHelper.IsNumericType(43.2m.GetType()));
    Assert.True(TypeHelper.IsNumericType(43.2d.GetType()));
    Assert.True(TypeHelper.IsNumericType(((short)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(((int)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(((long)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(((sbyte)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(2f.GetType()));
    Assert.True(TypeHelper.IsNumericType(((ushort)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(((uint)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(((ulong)2).GetType()));
    // ReSharper restore RedundantCast

    // Using GetType - nullable non-numeric types
    bool? nullableBool = true;
    Assert.False(TypeHelper.IsNumericType(nullableBool.GetType()));
    char? nullableChar = ' ';
    Assert.False(TypeHelper.IsNumericType(nullableChar.GetType()));
    DateTime? nullableDateTime = new DateTime(2009, 1, 1);
    Assert.False(TypeHelper.IsNumericType(nullableDateTime.GetType()));

    // Using GetType - nullable numeric types
    byte? nullableByte = 12;
    Assert.True(TypeHelper.IsNumericType(nullableByte.GetType()));
    decimal? nullableDecimal = 12.2m;
    Assert.True(TypeHelper.IsNumericType(nullableDecimal.GetType()));
    double? nullableDouble = 12.32;
    Assert.True(TypeHelper.IsNumericType(nullableDouble.GetType()));
    short? nullableInt16 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableInt16.GetType()));
    short? nullableInt32 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableInt32.GetType()));
    short? nullableInt64 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableInt64.GetType()));
    sbyte? nullableSByte = 12;
    Assert.True(TypeHelper.IsNumericType(nullableSByte.GetType()));
    float? nullableSingle = 3.2f;
    Assert.True(TypeHelper.IsNumericType(nullableSingle.GetType()));
    ushort? nullableUInt16 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableUInt16.GetType()));
    ushort? nullableUInt32 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableUInt32.GetType()));
    ushort? nullableUInt64 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableUInt64.GetType()));
}
  

Комментарии:

1. Чтобы добавить к этому могильному, если вы собираетесь определить IsNumericType для получения типа, почему бы не рекурсивно передать результат Nullable . Получить underlyingtype к той же функции и вернуть ее значение?

2. да … отличное предложение. так более элегантно. обновленный пост.

3. почему бы не объявить этот метод в статическом классе и сделать его доступным для ввода: public static bool IsNumeric(this Type type) { /*...*/ } ?

4. Хорошее решение, а также 1 для тестов. Определенно лучше, чем принятый ответ.

5. Хорошее решение, просто имейте в виду, что перечисление будет классифицироваться как целое число, используя приведенную выше логику

Ответ №2:

Вы можете узнать, является ли переменная числовой, используя Type.GetTypeCode() метод:

 TypeCode typeCode = Type.GetTypeCode(desiredType);

if (typeCode == TypeCode.Double || typeCode == TypeCode.Integer || ...)
     return true;
  

Вам нужно будет заполнить все доступные числовые типы в части «…» 😉

Подробнее здесь: перечисление кода типа

Комментарии:

1. Я надеялся, что мне не придется проверять каждый тип, но это работает, спасибо!

2. К вашему сведению, этот код не будет работать, если они являются типами с нулевым значением. В этом случае код типа возвращается как объект. Все еще пытаюсь выяснить, как обойти это. Кто-нибудь?

3. Лучше: Foreach (TypeCode typecode в new TypeCode[] { TypeCode . Double […] } если typecode == Type . GetTypeCode(desiredType) возвращает true; возвращает false;

4. почему вы, ребята, не могли просто сделать это для нас, чтобы мы могли копировать / вставлять?

5. @Ben, ты можешь сделать «if (1 is int)» в C #, а не «if (1.GetType() is int)». Надеюсь, вы поняли идею.

Ответ №3:

Отличная статья здесь исследует IsNumeric для C #.

Вариант 1:

Ссылка Microsoft.VisualBasic.dll , затем выполните следующие действия:

 if (Microsoft.VisualBasic.Information.IsNumeric("5"))
{
 //Do Something
}
  

Вариант 2:

 public static bool Isumeric (object Expression)
{
    bool f;
    ufloat64 a;
    long l;

    IConvertible iConvertible = null;
    if ( ((Expression is IConvertible)))
    {
       iConvertible = (IConvertible) Expression;
    }

    if (iConvertible == null)
{
   if ( ((Expression is char[])))
   {
       Expression = new String ((char[]) Expression);
       goto IL_002d; // hopefully inserted by optimizer
   }
   return 0;
}
IL_002d:
TypeCode typeCode = iConvertible.GetTypeCode ();
if ((typeCode == 18) || (typeCode == 4))
{
    string str = iConvertible.ToString (null);
   try
   {
        if ( (StringType.IsHexOrOctValue (str, l)))
   {
        f = true;
        return f;
   }
}
catch (Exception )
{
    f = false;
    return f;
};
return DoubleType.TryParse (str, a);
}
return Utils.IsNumericTypeCode (typeCode);
}

internal static bool IsNumericType (Type typ)
{
bool f;
TypeCode typeCode;
if ( (typ.IsArray))
{
    return 0;
}
switch (Type.GetTypeCode (typ))
{
case 3: 
case 6: 
case 7: 
case 9: 
case 11: 
case 13: 
case 14: 
case 15: 
   return 1;
};
return 0;
}
  

Ответ №4:

Если у вас есть ссылка на реальный объект, вот простое решение для C #, которое очень просто:

     /// <summary>
    /// Determines whether the supplied object is a .NET numeric system type
    /// </summary>
    /// <param name="val">The object to test</param>
    /// <returns>true=Is numeric; false=Not numeric</returns>
    public static bool IsNumeric(ref object val)
    {
        if (val == null)
            return false;

        // Test for numeric type, returning true if match
        if 
            (
            val is double || val is float || val is int || val is long || val is decimal || 
            val is short || val is uint || val is ushort || val is ulong || val is byte || 
            val is sbyte
            )
            return true;

        // Not numeric
        return false;
    }
  

Комментарии:

1. Я придумал нечто подобное. Могу ли я спросить, почему вы используете ключевое слово «ref» с аргументом val.

2. На самом деле это то же самое, что и решения на основе кода типа, описанные выше, за исключением того, что они медленнее…

Ответ №5:

Отдавая должное @SFun28 и @nawfal (спасибо!), Я использовал оба их ответа, немного изменил и придумал эти методы расширения:

 public static class ReflectionExtensions
{
    public static bool IsNullable(this Type type) {
        return
            type != null amp;amp;
            type.IsGenericType amp;amp; 
            type.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

    public static bool IsNumeric(this Type type) {
        if (type == null || type.IsEnum)
            return false;

        if (IsNullable(type))
            return IsNumeric(Nullable.GetUnderlyingType(type));

        switch (Type.GetTypeCode(type)) {
            case TypeCode.Byte:
            case TypeCode.Decimal:
            case TypeCode.Double:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.SByte:
            case TypeCode.Single:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
                return true;
            default:
                return false;
        }
    }
}
  

Комментарии:

1. не понимаю, почему if ‘тип. IsEnum’ возвращает false?

2. @Riga Я мог видеть, что перечисления являются серой областью, но я бы ошибся в сторону false . Допустим, вы создаете сериализатор JSON и хотите, чтобы перечисления были сериализованы в строки. В этом случае вы не хотели бы рассматривать их как число.

Ответ №6:

Я знаю, что это ОЧЕНЬ поздний ответ, но вот функция, которую я использую:

 public static bool IsNumeric(Type type)
{
    var t = Nullable.GetUnderlyingType(type) ?? type;
    return t.IsPrimitive || t == typeof(decimal);
}
  

Если вы хотите исключить char как числовой тип, вы можете использовать этот пример:

 return (t.IsPrimitive || t == typeof(decimal)) amp;amp; t != typeof(char);
  

Согласно MSDN:

Примитивными типами являются Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double и Single.

Примечание: Эта проверка включает IntPtr и UIntPtr .

Вот та же функция, что и общий метод расширения (я знаю, что это не работает для случая OP, но кто-то другой может счесть это полезным):

 public static bool IsNumeric<T>(this T value)
{
    var t = Nullable.GetUnderlyingType(value.GetType()) ?? value.GetType();
    return t.IsPrimitive || t == typeof(decimal);
}
  

Ответ №7:

Вот как MS реализовала это, в System.Dynamic.Utils.TypeUtils котором это внутренний класс. Оказывается, что они не считают System.Decimal числовой тип ( Decimal опущен в перечислении). И, что интересно, MS находит System.Char тип числовым. В противном случае это точно так же, как ответ SFun28. Я полагаю, что его ответ «более правильный».

 internal static bool IsNumeric(Type type)
{
    type = type.GetNonNullableType();
    if (!type.IsEnum)
    {
        switch (Type.GetTypeCode(type))
        {
        case TypeCode.Char:
        case TypeCode.SByte:
        case TypeCode.Byte:
        case TypeCode.Int16:
        case TypeCode.UInt16:
        case TypeCode.Int32:
        case TypeCode.UInt32:
        case TypeCode.Int64:
        case TypeCode.UInt64:
        case TypeCode.Single:
        case TypeCode.Double:
            return true;
        }
    }
    return false;
}

//where GetNonNullableType is defined as

internal static Type GetNonNullableType(this Type type)
{
    if (type.IsNullableType())
    {
        return type.GetGenericArguments()[0];
    }
    return type;
}

//where IsNullableType is defined as

internal static bool IsNullableType(this Type type)
{
    return type.IsGenericType amp;amp; type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
  

Комментарии:

1. Интересно, есть ли способ еще больше оптимизировать это, используя побитовые операции и еще много чего…

Ответ №8:

 ''// Return true if a type is a numeric type.
Private Function IsNumericType(ByVal this As Type) As Boolean
    ''// All the numeric types have bits 11xx set whereas non numeric do not.
    ''// That is if you include char type which is 4(decimal) = 100(binary).
    If this.IsArray Then Return False
    If (Type.GetTypeCode(this) And amp;HC) > 0 Then Return True
    Return False
End Function
  

Комментарии:

1. Совершенно неверно, SByte является числовым и имеет идентификатор 5, который равен ‘0101’, так что это неправильно.

Ответ №9:

Теперь вы можете использовать метод .NET Framework

 typeof(decimal?).IsNumericType()
  

Ответ №10:

Используйте тип.IsValueType() и TryParse():

 public bool IsInteger(Type t)
{
   int i;
   return t.IsValueType amp;amp; int.TryParse(t.ToString(), out i);
}
  

Комментарии:

1. «t» не является переменной рассматриваемого типа. Это тип, о котором идет речь. t никогда не будет числом в этом коде.