See the question and my original answer on StackOverflow

You can have a look at dot net core source code (I suppose - maybe I'm wrong - this part is common with .NET framework). A .NET String is internally defined as an unmanaged instance of "StringObject"

https://github.com/dotnet/coreclr/blob/8cc7e35dd0a625a3b883703387291739a148e8c8/src/vm/object.h

/*
 * StringObject
 *
 * Special String implementation for performance.   
 *
 *   m_StringLength - Length of string in number of WCHARs
 *   m_Characters   - The string buffer
 */

class StringObject : public Object
{
  ...
  private:
    DWORD   m_StringLength;
    WCHAR   m_Characters[0];
  ...
}

This is all unmanaged. It contains a buffer that happens to be defined as an array of wide (Unicode) characters, but that doesn't mean it cannot be used differently (like an array of bytes, or whatever, because unmanaged is a wild world).