문제

최근에 바이트 배열에서 데이터 타입을 읽기 위해 일반적인 방법을 만들어야하는 상황이 발생했습니다.

다음 수업을 만들었습니다.


public class DataStream
{
    public int Offset { get; set; }

    public byte[] Data { get; set; }

    public T Read<T>() where T : struct
    {
        unsafe
        {
            int dataLen = Marshal.SizeOf( typeof( T ) );
            IntPtr dataBlock = Marshal.AllocHGlobal( dataLen );


            Marshal.Copy( Data, Offset, dataBlock, dataLen );


            T type = *( ( T* )dataBlock.ToPointer() );

            Marshal.FreeHGlobal( dataBlock );

            Offset += dataLen;

            return type;
        }
    }
}

이제 할당 해제 문제를 제외 하고이 코드는이 메시지를 컴파일하지 않습니다.

Cannot take the address of, get the size of, or declare a pointer to a managed type ('T')

당신이 위의 작업을 수행 할 수 있어야하기 때문에 이상하게 보입니다. where T : struct 방법에 대한 제약.

이 코드가 끔찍하게 부정확하다면 일련의 바이트를 가져 와서 a에 캐스팅하는 간단한 방법이 있습니까?T' 유형?

감사!

도움이 되었습니까?

해결책

포인터 조작을 통해이 작업을 수행하는 대신 코드를 전환하여 사용해야합니다. mashal.ptrtostructure. 이 방법은이 시나리오를 위해 특별히 설계되었습니다.

다른 팁

답변이 이미 제공되었으므로 원래 코드가 왜 효과가 없었는지 설명하겠습니다.

방법의 위치 t : struct 제약 조건을 기반으로 위의 작업을 수행 할 수 있어야하기 때문에 이상해 보입니다.

설마. 당신은 원시 포인터를 가질 수 있습니다 관리되지 않는 유형. 이것은 c# 언어 사양 (18.2)에서 다음과 같이 정의됩니다.

참조 (참조 유형의 값)와 달리 포인터는 쓰레기 수집기에 의해 추적되지 않습니다. 가비지 수집기는 포인터와 그 데이터에 대한 지식이 없습니다. 이러한 이유로 포인터는 참조를 포함하는 기준 또는 구조물을 가리키는 것이 허용되지 않으며, 참조 유형의 포인터는 관리되지 않는 유형. an 관리되지 않는 유형 참조 유형이 아니며 모든 레벨의 중첩에서 기준 유형 필드를 포함하지 않는 모든 유형입니다. 다시 말해, an 관리되지 않는 유형 다음 중 하나입니다.

  • sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, 또는 bool.
  • 어느 열렬한 유형.
  • 어느 포인터 유형.
  • 모든 사용자 정의 구조체 유형 여기에는 필드가 포함되어 있습니다 관리되지 않는 유형 뿐.

따라서 몇 가지 제한 사항이 있으며 일반적인 방법이 있습니다. T:struct 특정 인스턴스화에 대해 그들을 준수 할 수도 있고 그렇지 않을 수도 있으므로 T* 불법입니다. 관리되지 않는 유형을 다루기 위해 특수한 일반 유형 매개 변수 제한 조건을 갖는 것이 좋을 것입니다. 그러나 CLR에는 아무것도 없습니다.

어느 시점에서 나는 썼다 이 기사 정확히 그렇게하는 방법을 설명하지만 마샬보다 더 빠릅니다. 코드 샘플은 동적 코드 생성을 사용하여 제네릭 타입 T를 비트 스트림으로 복사합니다.

가정 :

  • 순차적 또는 명시 적 구조 (그렇지 않으면 매우 나쁜 생각)
  • 정확한 데이터 크기 (사전 확인 및 던지기)

unsafe TStruct BytesToStructure<TStruct>(byte[] data) where TStruct : struct
{
    fixed (byte* dataPtr = data)
        return (TStruct)Marshal.PtrToStructure(new IntPtr(dataPtr), typeof(TStruct));
}

unsafe byte[] StructureToBytes<TStruct>(TStruct st) where TStruct : struct
{
    var bytes = new byte[Marshal.SizeOf(st)];
    fixed (byte* ptr = bytes) Marshal.StructureToPtr(st, new IntPtr(ptr), true);
    return bytes;
}

나는 똑같은 일을하기 위해 이것을 다시 썼다. http://www.codeproject.com/articles/33713/generic-binaryreader-and-binarywriter-extensions

그래도 Visual Studio 솔루션에 C ++/CLI 프로젝트를 추가해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top