How To Test if Type is Primitive
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.
Solution 1:
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:
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:
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:
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?)));
}