Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8901

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

$
0
0

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の許可が必要になります。

netstandard2.0
publicstaticReadOnlySpan<T>CreateReadOnlySpan<T>(inTreference,intlength)whereT:unmanaged{unsafe{returnnewReadOnlySpan<T>(Unsafe.AsPointer(refUnsafe.AsRef(inreference)),length);}}

.NET Standard 2.1 向け

netstandard2.1
publicstaticReadOnlySpan<T>CreateReadOnlySpan<T>(inTreference,intlength)whereT:unmanaged{returnMemoryMarshal.CreateReadOnlySpan(refUnsafe.AsRef(inreference),length);}

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

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

publicstaticclassReadOnlyRefUnsafe{[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticReadOnlySpan<T>CreateReadOnlySpan<T>(inTreference,intlength)whereT:unmanaged{#if BEFORE_NET_STANDARD21
unsafe{returnnewReadOnlySpan<T>(Unsafe.AsPointer(refUnsafe.AsRef(inreference)),length);}#else
returnMemoryMarshal.CreateReadOnlySpan(refUnsafe.AsRef(inreference),length);#endif
}[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticrefreadonlyTAdd<T>(inTsource,intelementOffset)=>refUnsafe.Add(refUnsafe.AsRef(insource),elementOffset);[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticrefreadonlyTAdd<T>(inTsource,IntPtrelementOffset)=>refUnsafe.Add(refUnsafe.AsRef(insource),elementOffset);[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticrefreadonlyTAddByteOffset<T>(inTsource,IntPtrbyteOffset)=>refUnsafe.AddByteOffset(refUnsafe.AsRef(insource),byteOffset);[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticboolAreSame<T>(inTleft,inTright)=>Unsafe.AreSame(refUnsafe.AsRef(inleft),refUnsafe.AsRef(inright));[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticrefreadonlyTToAs<TFrom,TTo>(inTFromsource)=>refUnsafe.As<TFrom,TTo>(refUnsafe.AsRef(insource));[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticIntPtrByteOffset<T>(inTorigin,inTtarget)=>Unsafe.ByteOffset(refUnsafe.AsRef(inorigin),refUnsafe.AsRef(intarget));[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticboolIsAddressGreaterThan<T>(inTleft,inTright)=>Unsafe.IsAddressGreaterThan(refUnsafe.AsRef(inleft),refUnsafe.AsRef(inright));[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticboolIsAddressLessThan<T>(inTleft,inTright)=>Unsafe.IsAddressLessThan(refUnsafe.AsRef(inleft),refUnsafe.AsRef(inright));[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticTRead<T>(inbytesource)=>As<byte,T>(insource);[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticrefreadonlyTSubtract<T>(inTsource,intelementOffset)=>refUnsafe.Subtract(refUnsafe.AsRef(insource),elementOffset);[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticrefreadonlyTSubtract<T>(inTsource,IntPtrelementOffset)=>refUnsafe.Subtract(refUnsafe.AsRef(insource),elementOffset);[MethodImpl(MethodImplOptions.AggressiveInlining)]publicstaticrefreadonlyTSubtractByteOffset<T>(inTsource,IntPtrbyteOffset)=>refUnsafe.SubtractByteOffset(refUnsafe.AsRef(insource),byteOffset);}

Viewing all articles
Browse latest Browse all 8901

Trending Articles