How do I tell if a type is a "simple" type? i.e. holds a single value
typeof(string).IsPrimitive == false
typeof(int).IsPrimitive == true
typeof(MyClass).IsClass == true
typeof(string).IsClass == true
typeof(string).IsByRef == false
typeof(MyClass).IsByRef == true // correction: should be false (see comments below)
I have a method that instantiates a new instance of T and, if it's a "complex" class, fills its properties from a set of source data values.
(a) If T is a simple type (e.g. a string or an int or anything else similar), a quick conversion from the source data to T is to be performed.
(b) If T is a class (but not something simple like string), then I'll use Activator.CreateInstance and do a bit of reflection to populate the fields.
Is there a quick and simple way to tell if I should use method (a) or method (b)? This logic will be used inside a generic method with T as the type argument.
Solution 1:
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));
}
Solution 2:
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));
}
Solution 3:
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;
}
Solution 4:
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
s -
decimal
s DateTime
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.
Solution 5:
Sorry to resurrect a really old thread, but since this still ranks high on web searches in Google, want to get a more direct and effective solution added:
if(System.Type.GetTypeCode(typeof(int)) == TypeCode.Object) {
// Do what you will...
}