Как проверить, является ли тип примитивным

У меня есть блок кода, который сериализует тип в тег Html.

Type t = typeof(T); // I pass <T> in as a paramter, where myObj is of type T
tagBuilder.Attributes.Add("class", t.Name);
foreach (PropertyInfo prop in t.GetProperties())
{
    object propValue = prop.GetValue(myObj, null);
    string stringValue = propValue != null ? propValue.ToString() : String.Empty;
    tagBuilder.Attributes.Add(prop.Name, stringValue);
}

Это отлично работает, за исключением того, что я хочу сделать это только для примитивных типов, таких как int, double, bool и т.д. и других типов, которые не являются примитивными, но могут быть легко сериализованы как string, Я хочу, чтобы он игнорировал все остальное, как Списки и другие настраиваемые типы.

Кто-нибудь может предложить, как я это делаю? Или мне нужно указать типы, которые я хочу разрешить, и включить тип свойства, чтобы узнать, разрешено ли это? Это немного грязно, так что было бы неплохо, если бы я был более аккуратным способом.

Ответ 1

Вы можете использовать свойство Type.IsPrimitive, но будьте осторожны, потому что есть некоторые типы, которые мы можем считать примитивами, но они не являются, например, Decimal и String.

Изменить 1: Добавлен пример кода

Вот пример кода:

if (t.IsPrimitive || t == typeof(Decimal) || t == typeof(String) || ... )
{
    // Is Primitive, or Decimal, or String
}

Изменить 2: Как @SLaks комментарии, есть и другие типы, которые, возможно, вы хотите рассматривать как примитивы. Я думаю, что вам придется добавлять эти варианты один за другим.

Изменить 3: IsPrimitive = (Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double и Single), Anther Primitive-Like для проверки (t == typeof (DateTime))

Ответ 2

Я просто нашел этот вопрос, ища аналогичное решение, и подумал, что вы можете быть заинтересованы в следующем подходе, используя System.TypeCode и System.Convert.

Легко сериализовать любой тип, который сопоставляется с System.TypeCode, отличным от System.TypeCode.Object, поэтому вы можете сделать:

object PropertyValue = ...
if(Convert.GetTypeCode(PropertyValue) != TypeCode.Object)
{
    string StringValue = Convert.ToString(PropertyValue);
    ...
}

Преимущество такого подхода заключается в том, что вам не нужно указывать любой другой приемлемый непримитивный тип. Вы также можете немного изменить приведенный выше код для обработки любого типа, который реализует IConvertible.

Ответ 3

Мы делаем это в нашем ORM:

Type t;
bool isPrimitiveType = t.IsPrimitive || t.IsValueType || (t == typeof(string));

Я знаю, что использование IsValueType не самый лучший вариант (у вас могут быть свои очень сложные структуры), но он работает в 99% случаях

Ответ 4

Из ответа @Ronnie Overby и комментария @jonathanconway я написал этот метод, который работает для Nullable и исключает пользовательские структуры.

public static bool IsSimpleType(Type type)
{
    return
        type.IsPrimitive ||
        new Type[] {
            typeof(Enum),
            typeof(String),
            typeof(Decimal),
            typeof(DateTime),
            typeof(DateTimeOffset),
            typeof(TimeSpan),
            typeof(Guid)
        }.Contains(type) ||
        Convert.GetTypeCode(type) != TypeCode.Object ||
        (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && IsSimpleType(type.GetGenericArguments()[0]))
        ;
}

С помощью следующей тестовой базы:

struct TestStruct
{
    public string Prop1;
    public int Prop2;
}

class TestClass1
{
    public string Prop1;
    public int Prop2;
}

[Test]
public void Test1()
{
    Assert.IsTrue(IsSimpleType(typeof(Enum)));
    Assert.IsTrue(IsSimpleType(typeof(String)));
    Assert.IsTrue(IsSimpleType(typeof(Char)));
    Assert.IsTrue(IsSimpleType(typeof(Guid)));

    Assert.IsTrue(IsSimpleType(typeof(Boolean)));
    Assert.IsTrue(IsSimpleType(typeof(Byte)));
    Assert.IsTrue(IsSimpleType(typeof(Int16)));
    Assert.IsTrue(IsSimpleType(typeof(Int32)));
    Assert.IsTrue(IsSimpleType(typeof(Int64)));
    Assert.IsTrue(IsSimpleType(typeof(Single)));
    Assert.IsTrue(IsSimpleType(typeof(Double)));
    Assert.IsTrue(IsSimpleType(typeof(Decimal)));

    Assert.IsTrue(IsSimpleType(typeof(SByte)));
    Assert.IsTrue(IsSimpleType(typeof(UInt16)));
    Assert.IsTrue(IsSimpleType(typeof(UInt32)));
    Assert.IsTrue(IsSimpleType(typeof(UInt64)));

    Assert.IsTrue(IsSimpleType(typeof(DateTime)));
    Assert.IsTrue(IsSimpleType(typeof(DateTimeOffset)));
    Assert.IsTrue(IsSimpleType(typeof(TimeSpan)));

    Assert.IsFalse(IsSimpleType(typeof(TestStruct)));
    Assert.IsFalse(IsSimpleType(typeof(TestClass1)));

    Assert.IsTrue(IsSimpleType(typeof(Nullable<Char>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Guid>)));

    Assert.IsTrue(IsSimpleType(typeof(Nullable<Boolean>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Byte>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Int16>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Int32>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Int64>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Single>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Double>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Decimal>)));

    Assert.IsTrue(IsSimpleType(typeof(Nullable<SByte>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt16>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt32>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt64>)));

    Assert.IsTrue(IsSimpleType(typeof(Nullable<DateTime>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<DateTimeOffset>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<TimeSpan>)));

    Assert.IsFalse(IsSimpleType(typeof(Nullable<TestStruct>)));
}

Ответ 5

Вот как я это сделал.

   static class PrimitiveTypes
   {
       public static readonly Type[] List;

       static PrimitiveTypes()
       {
           var types = new[]
                          {
                              typeof (Enum),
                              typeof (String),
                              typeof (Char),
                              typeof (Guid),

                              typeof (Boolean),
                              typeof (Byte),
                              typeof (Int16),
                              typeof (Int32),
                              typeof (Int64),
                              typeof (Single),
                              typeof (Double),
                              typeof (Decimal),

                              typeof (SByte),
                              typeof (UInt16),
                              typeof (UInt32),
                              typeof (UInt64),

                              typeof (DateTime),
                              typeof (DateTimeOffset),
                              typeof (TimeSpan),
                          };


           var nullTypes = from t in types
                           where t.IsValueType
                           select typeof (Nullable<>).MakeGenericType(t);

           List = types.Concat(nullTypes).ToArray();
       }

       public static bool Test(Type type)
       {
           if (List.Any(x => x.IsAssignableFrom(type)))
               return true;

           var nut = Nullable.GetUnderlyingType(type);
           return nut != null && nut.IsEnum;
       }
   }

Ответ 6

Также хорошая возможность:

private static bool IsPrimitiveType(Type type)
{
    return (type == typeof(object) || Type.GetTypeCode(type) != TypeCode.Object);
}

Ответ 7

Предполагая, что у вас есть сигнатура функции:

void foo<T>() 

Вы можете добавить общее ограничение, чтобы разрешить типы значений:

void foo<T>() where T : struct

Обратите внимание, что это позволяет использовать не только примитивные типы для T, но и любой тип значения.

Ответ 8

Мне нужно было сериализовать типы для их экспорта в XML. Чтобы сделать это, я повторил этот объект и выбрал поля, которые были примитивными, перечисляемыми, типами значений или сериализуемыми. Это было результатом моего запроса:

Type contextType = context.GetType();

var props = (from property in contextType.GetProperties()
                         let name = property.Name
                         let type = property.PropertyType
                         let value = property.GetValue(context,
                                     (BindingFlags.GetProperty | BindingFlags.GetField | BindingFlags.Public),
                                     null, null, null)
                         where (type.IsPrimitive || type.IsEnum || type.IsValueType || type.IsSerializable)
                         select new { Name = name, Value = value});

Я использовал LINQ для повторения типов, а затем их имя и значение сохранялось в таблице символов. Ключ находится в разделе "where", которое я выбрал для отражения. Я выбрал примитивные, перечислимые типы значений и сериализуемые типы. Это позволило для строк и объектов DateTime пройти, как я ожидал.

Ура!

Ответ 9

Я просто хочу поделиться своим решением. Возможно, это полезно для всех.

public static bool IsPrimitiveType(Type fieldType)
{
   return fieldType.IsPrimitive || fieldType.Namespace.Equals("System");
}

Ответ 10

Это то, что у меня есть в моей библиотеке. Комментарии приветствуются.

Я сначала проверяю IsValueType, так как он обрабатывает большинство типов, а затем String, так как он является вторым наиболее распространенным. Я не могу придумать примитив, который не является типом значений, поэтому я не знаю, попала ли эта нога когда-либо.

  Public Shared Function IsPersistable(Type As System.Type) As Boolean
    With TypeInformation.UnderlyingType(Type)
      Return .IsValueType OrElse Type = GetType(String) OrElse .IsPrimitive
    End With
  End Function

  Public Shared Function IsNullable(ByVal Type As System.Type) As Boolean
    Return (Type.IsGenericType) AndAlso (Type.GetGenericTypeDefinition() Is GetType(Nullable(Of )))
  End Function

  Public Shared Function UnderlyingType(ByVal Type As System.Type) As System.Type
    If IsNullable(Type) Then
      Return Nullable.GetUnderlyingType(Type)
    Else
      Return Type
    End If
  End Function

Тогда я могу использовать его следующим образом:

  Public Shared Function PersistableProperties(Item As System.Type) As IEnumerable(Of System.Reflection.PropertyInfo)
    Return From PropertyInfo In Item.GetProperties()
                     Where PropertyInfo.CanWrite AndAlso (IsPersistable(PropertyInfo.PropertyType))
                     Select PropertyInfo
  End Function

Ответ 11

public static bool IsPrimitiveType(object myObject)
{
   var myType = myObject.GetType();
   return myType.IsPrimitive || myType.Namespace == null ||  myType.Namespace.Equals("System");
}

Не забудьте проверить пространство имен NULL, поскольку анонимным объектам не присвоено пространство имен

Ответ 12

Вот еще один жизнеспособный вариант.

public static bool CanDirectlyCompare(Type type)
{
    return typeof(IComparable).IsAssignableFrom(type) || type.IsPrimitive || type.IsValueType;
}