How To Test if Type is Primitive

C#ReflectionPrimitive Types

C# Problem Overview


I have a block of code that serializes a type into a Html tag.

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

This works great, except I want it to only do this for primitive types, like int, double, bool etc, and other types that aren't primitive but can be serialized easily like string. I want it to ignore everything else like Lists & other custom types.

Can anyone suggest how I do this? Or do I need to specify the types I want to allow somewhere and switch on the property's type to see if it's allowed? That's a little messy, so it'd be nice if I there was a tidier way.

C# Solutions


Solution 1 - C#

You can use the property Type.IsPrimitive, but be carefull because there are some types that we can think that are primitives, but they aren´t, for example Decimal and String.

Edit 1: Added sample code

Here is a sample code:

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

Edit 2: As @SLaks comments, there are other types that maybe you want to treat as primitives, too. I think that you´ll have to add this variations one by one.

Edit 3: IsPrimitive = (Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single), Anther Primitive-Like type to check (t == typeof(DateTime))

Solution 2 - C#

I just found this question while looking for a similar solution, and thought you might be interested in the following approach using System.TypeCode and System.Convert.

It is easy to serialize any type that is mapped to a System.TypeCode other than System.TypeCode.Object, so you could do:

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

The advantage with this approach is you don't have to name every other acceptable non-primitive type. You could also modify the above code slightly to handle any type that implements IConvertible.

Solution 3 - C#

We do it like this in our ORM:

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

I know that using IsValueType is not the best option (you can have your own very complex structs) but it works in 99% cases (and includes Nullables).

Solution 4 - C#

From @Ronnie Overby response and @jonathanconway comment, I wrote this method that works for Nullable, and exclude user structs.

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

With the following TestCase :

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

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

enum TestEnum { TheValue }

[Test]
public void Test1()
{
    Assert.IsTrue(IsSimpleType(typeof(TestEnum)));
    Assert.IsTrue(IsSimpleType(typeof(string)));
    Assert.IsTrue(IsSimpleType(typeof(char)));
    Assert.IsTrue(IsSimpleType(typeof(Guid)));
        
    Assert.IsTrue(IsSimpleType(typeof(bool)));
    Assert.IsTrue(IsSimpleType(typeof(byte)));
    Assert.IsTrue(IsSimpleType(typeof(short)));
    Assert.IsTrue(IsSimpleType(typeof(int)));
    Assert.IsTrue(IsSimpleType(typeof(long)));
    Assert.IsTrue(IsSimpleType(typeof(float)));
    Assert.IsTrue(IsSimpleType(typeof(double)));
    Assert.IsTrue(IsSimpleType(typeof(decimal)));
        
    Assert.IsTrue(IsSimpleType(typeof(sbyte)));
    Assert.IsTrue(IsSimpleType(typeof(ushort)));
    Assert.IsTrue(IsSimpleType(typeof(uint)));
    Assert.IsTrue(IsSimpleType(typeof(ulong)));
        
    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(TestEnum?)));
    Assert.IsTrue(IsSimpleType(typeof(char?)));
    Assert.IsTrue(IsSimpleType(typeof(Guid?)));
        
    Assert.IsTrue(IsSimpleType(typeof(bool?)));
    Assert.IsTrue(IsSimpleType(typeof(byte?)));
    Assert.IsTrue(IsSimpleType(typeof(short?)));
    Assert.IsTrue(IsSimpleType(typeof(int?)));
    Assert.IsTrue(IsSimpleType(typeof(long?)));
    Assert.IsTrue(IsSimpleType(typeof(float?)));
    Assert.IsTrue(IsSimpleType(typeof(double?)));
    Assert.IsTrue(IsSimpleType(typeof(decimal?)));
        
    Assert.IsTrue(IsSimpleType(typeof(sbyte?)));
    Assert.IsTrue(IsSimpleType(typeof(ushort?)));
    Assert.IsTrue(IsSimpleType(typeof(uint?)));
    Assert.IsTrue(IsSimpleType(typeof(ulong?)));
        
    Assert.IsTrue(IsSimpleType(typeof(DateTime?)));
    Assert.IsTrue(IsSimpleType(typeof(DateTimeOffset?)));
    Assert.IsTrue(IsSimpleType(typeof(TimeSpan?)));
        
    Assert.IsFalse(IsSimpleType(typeof(TestStruct?)));
}

Solution 5 - C#

Here's how I did it.

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

2020 update

Derived from @Xav987's answer, this performs better and has less code.

	static readonly ConcurrentDictionary<Type, bool> IsSimpleTypeCache = new ConcurrentDictionary<System.Type, bool>();

	public static bool IsSimpleType(Type type)
	{
		return IsSimpleTypeCache.GetOrAdd(type, t =>
			type.IsPrimitive ||
			type.IsEnum ||
			type == typeof(string) ||
			type == typeof(decimal) ||
			type == typeof(DateTime) ||
			type == typeof(DateTimeOffset) ||
			type == typeof(TimeSpan) ||
			type == typeof(Guid) ||
			IsNullableSimpleType(type));

		static bool IsNullableSimpleType(Type t)
		{
			var underlyingType = Nullable.GetUnderlyingType(t);
			return underlyingType != null && IsSimpleType(underlyingType);
		}
	}

Solution 6 - C#

Also a good possibility:

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

Solution 7 - C#

Assuming you have a function signature like this:

void foo<T>() 

You could add a generic constraint to allow value types only:

void foo<T>() where T : struct

Notice that this allows not only primitive types for T, but any value type.

Solution 8 - C#

I had a need to serialize types for the purposes of exporting them to XML. To do this, I iterated through the object and opted for fields that were primitive, enum, value types or serializable. This was the result of my query:

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

I used LINQ to iterate through the types, then get their name and value to store in a symbol table. The key is in the 'where' clause that I chose for reflection. I chose primitive, enumerated, value types and serializable types. This allowed for strings and DateTime objects to come through as I expected.

Cheers!

Solution 9 - C#

This is what I have in my library. Comments are welcome.

I check IsValueType first, since it handles most types, then String, since it's the second most common. I can't think of a primitive that isn't a value type, so I don't know if that leg of the if ever gets hit.

  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

Then I can use it like this:

  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

Solution 10 - C#

I just want to share my solution. Perhaps it's useful to anyone.

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

Solution 11 - C#

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

Don't forget to check NULL namespace, because anonymous objects don't have assigned namespace

Solution 12 - C#

Here is another viable option.

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

Solution 13 - C#

An Extension method which works only for Primitive types, String, Decimal, DateTime, DateTimeOffset, TimeSpan and Guid.
You can add type.IsValueType in OR if you want to include generics, structs and enums.

    private static readonly Type[] PrimitiveLikeTypes = new[]
    {
                typeof(string),
                typeof(decimal),
                typeof(DateTime),
                typeof(DateTimeOffset),
                typeof(TimeSpan),
                typeof(Guid)
    };

    /// <summary>
    /// Determine whether a type is simple (Primitive, String, Decimal, DateTime, etc) 
    /// or complex (i.e. structs, Enums, custom class with public properties and methods).
    /// Returns false for structs and Enums
    /// </summary>
    /// <param name="type">System.Type</param>
    /// <returns> boolean value indicating whether the type is simple or not</returns>
    public static bool IsSimpleType(this Type type)
    {
        return type.IsPrimitive || PrimitiveLikeTypes.Contains(type);
    }
    

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDaveDevView Question on Stackoverflow
Solution 1 - C#JavierView Answer on Stackoverflow
Solution 2 - C#Michael PetitoView Answer on Stackoverflow
Solution 3 - C#Alex from JitbitView Answer on Stackoverflow
Solution 4 - C#Xav987View Answer on Stackoverflow
Solution 5 - C#Ronnie OverbyView Answer on Stackoverflow
Solution 6 - C#k3floView Answer on Stackoverflow
Solution 7 - C#eWolfView Answer on Stackoverflow
Solution 8 - C#JFalconView Answer on Stackoverflow
Solution 9 - C#toddmoView Answer on Stackoverflow
Solution 10 - C#BahamutView Answer on Stackoverflow
Solution 11 - C#iDuskoView Answer on Stackoverflow
Solution 12 - C#user2023116View Answer on Stackoverflow
Solution 13 - C#Jay ShahView Answer on Stackoverflow