Как проверить, является ли тип примитивным - PullRequest
149 голосов
/ 14 марта 2010

У меня есть блок кода, который сериализует тип в 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 , Я хочу, чтобы он игнорировал все остальное, например списки и другие пользовательские типы.

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

Ответы [ 12 ]

166 голосов
/ 14 марта 2010

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

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

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

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

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

Редактировать 3: IsPrimitive = (логическое значение, байт, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double и Single), Anther Primitive-подобный тип для проверки (t == typeof (DateTime))

51 голосов
/ 19 апреля 2010

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

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

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

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

44 голосов
/ 14 мая 2012

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

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

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

28 голосов
/ 01 сентября 2015

Из ответа @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]))
        ;
}

Со следующим TestCase:

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>)));
}
15 голосов
/ 22 марта 2013

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

   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;
       }
   }
5 голосов
/ 14 июня 2013

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

private static bool IsPrimitiveType(Type type)
{
    return (type == typeof(object) || Type.GetTypeCode(type) != TypeCode.Object);
}
3 голосов
/ 14 марта 2010

Предположим, у вас есть подпись функции, подобная этой:

void foo<T>() 

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

void foo<T>() where T : struct

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

2 голосов
/ 18 мая 2013

Мне нужно было сериализовать типы для экспорта их в 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, чтобы перебрать типы, а затем получить их имя и значение для хранения в таблице символов. Ключ в предложении «где», которое я выбрал для размышления. Я выбрал примитивные, перечислимые, типы значений и сериализуемые типы. Это позволило проходить строки и объекты DateTime, как я и ожидал.

ура!

1 голос
/ 27 августа 2013

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

public static bool IsPrimitiveType(Type fieldType)
{
   return fieldType.IsPrimitive || fieldType.Namespace.Equals("System");
}
1 голос
/ 22 мая 2012

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

Сначала я проверяю 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
...