How do I tell if a type is a "simple" type? i.e. holds a single value
String is probably a special case.
I think I would do.....
bool IsSimple(Type type)
{
return type.IsPrimitive
|| type.Equals(typeof(string));
}
Edit:
Sometimes you need to cover some more cases, like enums and decimals. Enums are a special kind of type in C#. Decimals are structs like any other. The problem with the structs is that they may be complex, they may be user defined types, they may be just a number. So you don't have any other chance than knowing them to differentiate.
bool IsSimple(Type type)
{
return type.IsPrimitive
|| type.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal));
}
Handling nullable counterparts are also a bit tricky. The nullable itself is a struct.
bool IsSimple(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// nullable type, check if the nested type is simple.
return IsSimple(type.GetGenericArguments()[0]);
}
return type.IsPrimitive
|| type.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal));
}
Test:
Assert.IsTrue(IsSimple(typeof(string)));
Assert.IsTrue(IsSimple(typeof(int)));
Assert.IsTrue(IsSimple(typeof(decimal)));
Assert.IsTrue(IsSimple(typeof(float)));
Assert.IsTrue(IsSimple(typeof(StringComparison))); // enum
Assert.IsTrue(IsSimple(typeof(int?)));
Assert.IsTrue(IsSimple(typeof(decimal?)));
Assert.IsTrue(IsSimple(typeof(StringComparison?)));
Assert.IsFalse(IsSimple(typeof(object)));
Assert.IsFalse(IsSimple(typeof(Point))); // struct in System.Drawing
Assert.IsFalse(IsSimple(typeof(Point?)));
Assert.IsFalse(IsSimple(typeof(StringBuilder))); // reference type
Note to .NET Core
As DucoJ points out in his answer, some of the used methods are not available on the class Type
in .NET core anymore.
Fixed code (I hope it works, I couldn't try myself. Otherwise please comment):
bool IsSimple(Type type)
{
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// nullable type, check if the nested type is simple.
return IsSimple(typeInfo.GetGenericArguments()[0]);
}
return typeInfo.IsPrimitive
|| typeInfo.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal));
}
In Addition to Stefan Steinegger answer: In .NET Core the .IsPrimitive etc. are no longer members of Type, they are now members of TypeInfo. So his solution will then become:
bool IsSimple(TypeInfo type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// nullable type, check if the nested type is simple.
return IsSimple((type.GetGenericArguments()[0]).GetTypeInfo());
}
return type.IsPrimitive
|| type.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal));
}
There is a more general type than primitive, the ValueType encompasses a lot more than primitive, such as enums, decimal, and other such things ValueType. Below is a function I wrote to identify complex types, that may fit your needs.
public static bool IsComplex(Type typeIn)
{
if (typeIn.IsSubclassOf(typeof(System.ValueType)) || typeIn.Equals(typeof(string))) //|| typeIn.IsPrimitive
return false;
else
return true;
}
Using a solution based on TypeConverter
is also a nice and simple way to model this.
Say you have this implementation for instance:
public static bool IsSimple(this Type type) =>
TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string));
This returns true
for:
- All primitive types
- All enums
string
sdecimal
sDateTime
DateTimeOffset
TimeSpan
Uri
Guid
Nullable<>
of any of the types above- numerous other types that have native
TypeConverter
s implemented (see here on theDerived
section)
This approach works well since most frameworks support TypeConverter
s natively, like XML and Json serialization libraries, and you can then use the same converter to parse the values while reading.