The fastest way to check if a type is blittable?
The excellent code by @IllidanS4 on this page incorrectly returns false
for arrays where the element is a blittable formatted type, meaning that the array is blittable also. Starting from that example, I fixed that problem and added handling for a few more mishandled cases, such as:
T[]
whereT
: formatted-type (just mentioned)- jagged arrays
int[][][]...
- enums (but not
System.Enum
ittself) - interfaces, abstract types
- generic types (never blittable).
I also added made the cases for avoiding the expensive Exception
block a bit more exhaustive and ran unit tests for all the different kinds of types I could think of.
public static bool IsBlittable(this Type T)
{
while (T.IsArray)
T = T.GetElementType();
bool b;
if (!((b = T.IsPrimitive || T.IsEnum) || T.IsAbstract || T.IsAutoLayout || T.IsGenericType))
try
{
GCHandle.Alloc(FormatterServices.GetUninitializedObject(T), GCHandleType.Pinned).Free();
b = true;
}
catch { }
return b;
}
The nice caching mechanism from the other answer should be used as-is.
I'm using generic class to cache results. Test is done in same way (trying to allocate pinned handle).
public static class BlittableHelper<T>
{
public static readonly bool IsBlittable;
static BlittableHelper()
{
try
{
// Class test
if (default(T) != null)
{
// Non-blittable types cannot allocate pinned handle
GCHandle.Alloc(default(T), GCHandleType.Pinned).Free();
IsBlittable = true;
}
}
catch { }
}
}
The current answer works for the questioner's case but, according to the specification, arrays of blittable value types are also blittable types themselves. Extended Ondřej's method a bit, so it takes this into account, and also works for reference types:
public static bool IsBlittable<T>()
{
return IsBlittableCache<T>.Value;
}
public static bool IsBlittable(Type type)
{
if(type.IsArray)
{
var elem = type.GetElementType();
return elem.IsValueType && IsBlittable(elem);
}
try{
object instance = FormatterServices.GetUninitializedObject(type);
GCHandle.Alloc(instance, GCHandleType.Pinned).Free();
return true;
}catch{
return false;
}
}
private static class IsBlittableCache<T>
{
public static readonly bool Value = IsBlittable(typeof(T));
}
As a side effect, this returns (albeit correctly) false
for string
, because GetUninitializedObject
can't create it. Assuming Alloc
really checks for blittability (except for string
), this should be reliable.