MissingFieldException with Unsafe Generics Array from external assembly

I’ve encountered a problem with using unsafe generic arrays in Unity.
When a class from an external assembly uses a field with the type T*[] (where T is an unmanaged generic type), Unity throws a MissingFieldException at runtime when trying to instantiate the class, even though the field is accessible via reflection.

Here’s a minimal example:

namespace GenericUnsafeTest
{
    public unsafe class SomeClass<T> where T : unmanaged
    {
        private T*[] _collection;

        public SomeClass(int length)
        {
            _collection = new T*[length];
        }
    }
}

Instantiating this class in Unity like so:

var instance = new GenericUnsafeTest.SomeClass<int>(10);

Results in the following error:

MissingFieldException: Field not found: !0*[] GenericUnsafeTest.SomeClass`1._collection Due to: Could not find field in class

Notably:

  • The issue only occurs when the class is compiled into a DLL and imported into Unity.
  • If the same code is placed directly in the Unity project, it works as expected.
  • Removing the generic parameter (changing T*[] to a specific type like int*[]) also resolves the issue
  • There is also no issues using a non collection generic pointer like T*
  • The issue is reproduced on Unity 2022 LTS and Unity 6 LTS (haven’t tested on any other version)

It seems Unity’s runtime has trouble handling the combination of unsafe pointers and generic collections when loaded from an external assembly.

Any insights or workarounds would be appreciated!

For me, the solution was to replace the generic pointer arrays (T*[]) with an IntPtr[] and cast them back to generic pointers whenever needed. However, this approach is far from ideal. It sacrifices type safety in my unsafe code and only worked because I have access to the source code.

To provide additional context:

  • Referencing the built DLL in any .NET application works correctly, so this is clearly not a DLL compilation issue.
  • The issue occurs not only when this type is used as a field but also when invoking a method that includes this type in its signature.