Span<T>, Memory<T> - slog(완료)

이 글이 저에겐 실질적으로 도움이 됐습니다. 개념적으로 이해하는 것과 손이 나가는 것은 조금 다른 감각인 것 같네요. 마치 영어의 독해와 회화 같이요.

참고하여 Span 확장 클래스를 만들어 봤습니다. 같이 보시죠.

public static class SpanExtension
{
    public static ReadOnlySpan<byte> AsReadOnlyBytes<T>(this ref T @this)
        where T : struct
    {
        var span = MemoryMarshal.CreateReadOnlySpan(ref @this, 1);
        return MemoryMarshal.Cast<T, byte>(span);
    }

    public static ReadOnlySpan<byte> AsReadOnlyBytes<T>(this T[] @this)
        where T : struct
    {
        return MemoryMarshal.Cast<T, byte>(@this);
    }

    public static Span<byte> AsBytes<T>(this ref T @this)
        where T : struct
    {
        var span = MemoryMarshal.CreateSpan(ref @this, 1);
        return MemoryMarshal.Cast<T, byte>(span);
    }

    public static Span<byte> AsBytes<T>(this T[] @this)
        where T : struct
    {
        return MemoryMarshal.Cast<T, byte>(@this);
    }
}

확장을 보시면 MemoryMarshal의 기능을 이용한 것 뿐이지만, 강력합니다. 이 확장을 이용해 다음과 같이 Stream에 쓰거나 읽는 코드를 단순화 하였습니다.

    public void Write(Stream s)
    {
        s.Write(체결시각.AsReadOnlyBytes());
        s.Write(체결가.AsReadOnlyBytes());
        s.Write(체결수량.AsReadOnlyBytes());
        s.Write(매수호가잔량.AsReadOnlyBytes());
        s.Write(매도호가잔량.AsReadOnlyBytes());
    }

    public static bool Read(Stream s, ref 실시간시세 v)
    {

        var length = s.Read(v.체결시각.AsBytes());
        if (length == 0)
            return false;
        
        s.Read(v.체결가.AsBytes());
        s.Read(v.체결수량.AsBytes());
        v.매수호가잔량 = new decimal[5];
        s.Read(v.매수호가잔량.AsBytes());
        v.매도호가잔량 = new decimal[5];
        s.Read(v.매도호가잔량.AsBytes());

        return true;
    }

AsReadOnlyBytes()를 통해 메모리 할당 없이 해당 필드를 ReadOnlySpan로 변환하여 쓰기를 합니다.
더욱 재밌는 것은 AsBytes()를 통해 해당 필드의 메모리 위치를 Span로 변환하여 바로 읽기할 수 있다는 것입니다.

2개의 좋아요