ref readonly(inパラメーター修飾子)からReadOnlySpanを構築する

C# 7.2から追加された読み取り専用参照(`ref readonly T`)ですが、残念ながらそのまま`ReadOnlySpan<T>`を構築出来ません。

読み取り専用ではない通常の参照(`ref T`)であれば、`Span<T>`を`MemoryMarshal.CreateSpan`で構築出来ますが、`ReadOnlySpan<T>`を構築する`MemoryMarshal.CreateReadOnlySpan`の引数は__`ref T`__となっているため、読み取り専用参照(`ref readonly T`)からは構築出来ません。
また、.NET Standard 2.0では`MemoryMarshal.CreateReadOnlySpan`がありません。

# ReadOnlySpanを構築する方法

読み取り専用参照から通常の参照を得るため、`System.Runtime.CompilerServices.Unsafe.AsRef(in reference)`を使用します。
NugetでSystem.Runtime.CompilerServicesを追加する必要があります。

## .NET Standard 2.0 向け
`MemoryMarshal.CreateReadOnlySpan`が無いため、ポインターから`ReadOnlySpan<T>`を構築します。
Unsafeの許可が必要になります。

追記: 参照先がスタック上に存在しないと不正なポインターとなりクラッシュする可能性が有ります。
**配列やclassに含まれる値型の参照から`ReadOnlySpan`を構築してはいけません。**

```cs:netstandard2.0
        public static ReadOnlySpan<T> CreateReadOnlySpan<T>(in T reference, int length)
            where T : unmanaged
        {
            unsafe
            {
                return new ReadOnlySpan<T>(Unsafe.AsPointer(ref Unsafe.AsRef(in reference)), length);
            }
        }
```

## .NET Standard 2.1 向け
```cs:netstandard2.1
        public static ReadOnlySpan<T> CreateReadOnlySpan<T>(in T reference, int length)
            where T : unmanaged
        {
            return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in reference), length);
        }
```

# 他のユーティリティメソッド

オマケです。
Unsafeクラスのメソッドはほぼ通常の参照(`ref T`)しか引数に取らないため、読み取り専用参照を扱うメソッドを用意してみました。

```cs
    public static class ReadOnlyRefUnsafe
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ReadOnlySpan<T> CreateReadOnlySpan<T>(in T reference, int length)
            where T : unmanaged
        {
#if BEFORE_NET_STANDARD21
            unsafe
            {
                return new ReadOnlySpan<T>(Unsafe.AsPointer(ref Unsafe.AsRef(in reference)), length);
            }
#else
            return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in reference), length);
#endif
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ref readonly T Add<T>(in T source, int elementOffset)
            => ref Unsafe.Add(ref Unsafe.AsRef(in source), elementOffset);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ref readonly T Add<T>(in T source, IntPtr elementOffset)
            => ref Unsafe.Add(ref Unsafe.AsRef(in source), elementOffset);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ref readonly T AddByteOffset<T>(in T source, IntPtr byteOffset)
            => ref Unsafe.AddByteOffset(ref Unsafe.AsRef(in source), byteOffset);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool AreSame<T>(in T left, in T right)
            => Unsafe.AreSame(ref Unsafe.AsRef(in left), ref Unsafe.AsRef(in right));

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ref readonly TTo As<TFrom, TTo>(in TFrom source)
            => ref Unsafe.As<TFrom, TTo>(ref Unsafe.AsRef(in source));

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static IntPtr ByteOffset<T>(in T origin, in T target)
            => Unsafe.ByteOffset(ref Unsafe.AsRef(in origin), ref Unsafe.AsRef(in target));

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool IsAddressGreaterThan<T>(in T left, in T right)
            => Unsafe.IsAddressGreaterThan(ref Unsafe.AsRef(in left), ref Unsafe.AsRef(in right));

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool IsAddressLessThan<T>(in T left, in T right)
            => Unsafe.IsAddressLessThan(ref Unsafe.AsRef(in left), ref Unsafe.AsRef(in right));

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static T Read<T>(in byte source)
            => As<byte, T>(in source);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ref readonly T Subtract<T>(in T source, int elementOffset)
            => ref Unsafe.Subtract(ref Unsafe.AsRef(in source), elementOffset);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ref readonly T Subtract<T>(in T source, IntPtr elementOffset)
            => ref Unsafe.Subtract(ref Unsafe.AsRef(in source), elementOffset);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ref readonly T SubtractByteOffset<T>(in T source, IntPtr byteOffset)
            => ref Unsafe.SubtractByteOffset(ref Unsafe.AsRef(in source), byteOffset);
    }
```