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[] where T : 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.