C\#Protobuf 가 0 분배 메모리 의 직렬 화 를 어떻게 하 는 지 상세 하 게 설명 합 니 다.

5445 단어 C#Protobuf서열 화
제목 은 간단 하 다.바로 IMessage 대상 이 어떻게 Byte 가 되 는 지[]이다.
답 1:

msg.ToByteArray()
이것 은 틀림없이 우리 의 요구 에 부합 되 지 않 을 것 이다.
정 답 2:

using var memoryStream = new MemoryStream();
using var codedOutputStream = new CodedOutputStream(memoryStream);
msg.WriteTo(codedOutputStream);
codedOutputStream.Flush();
memoryStream.ToArray();
이 안 에는 memory Stream,coded Output Stream,그리고 ToArray 가 하나의 대상 을 만 들 었 고 Memory Stream 내부 에 byte[]대상 이 하나 더 생 길 수 있 습 니 다.
요구 에 부합 되 지 않다
답 3:
어떤 분 이 Memory Stream 에 byte[]slice 를 전달 해서 Memory Stream 에 직접 byte[]를 사용 하 라 고 하 셨 어 요.

var bytes = new byte[msg.CalculateSize()];
using var memoryStream = new MemoryStream();
using var codedOutputStream = new CodedOutputStream(memoryStream);
msg.WriteTo(codedOutputStream);
codedOutputStream.Flush();
이번 소식 은 바로 bytes 안 으로 서열 화 되 었 다.그러나 memory Stream 대상,codec OutputStream 과 memory Stream 내부 의 byte[]가 모두 남아 있 었 다.나 는 대상 을 서열 화 했 지만 쓰레기 대상 이 3 개 생 겼 다. 
그래서 CodedOutputStream 류 를 자세히 살 펴 보 겠 습 니 다.

    /// <summary>
    /// Creates a new CodedOutputStream that writes directly to the given
    /// byte array. If more bytes are written than fit in the array,
    /// OutOfSpaceException will be thrown.
    /// </summary>
    public CodedOutputStream(byte[] flatArray) : this(flatArray, 0, flatArray.Length)
    {
    }

    /// <summary>
    /// Creates a new CodedOutputStream that writes directly to the given
    /// byte array slice. If more bytes are written than fit in the array,
    /// OutOfSpaceException will be thrown.
    /// </summary>
    private CodedOutputStream(byte[] buffer, int offset, int length)
    {
      this.output = null;
      this.buffer = buffer;
      this.position = offset;
      this.limit = offset + length;
      leaveOpen = true; // Simple way of avoiding trying to dispose of a null reference
    }

byte[]의 구조 함 수 를 제 공 했 지만 slice 의 구조 함 수 를 제공 하지 않 았 습 니 다.다행히 개인 적 인 구조 함수 가 있 습 니 다.
답 4:
여 기 는 코드 를 쓰 지 않 습 니 다.아마도 개인 구조 함 수 를 반사 하여 Coded Output Stream 대상 을 구성 하여 Memory Stream 과 그 내부 의 by te 를 절약 하 는 것 입 니 다[].
이제 답 과 비슷 해 졌 습 니 다. 
그렇다면 우리 의 문 제 는 CodedOutputStream 마저 줄 일 수 있 느 냐 하 는 것 이다.
정 답 5 가 왔 다.
자세히 살 펴 보 니 이 종 류 는 Stream 을 사용 하지 않 은 상태 에서 buffer,limit,position 몇 명의 멤버 만 수정 하면 됩 니 다.private 멤버 이지 만 C\#는 수정 할 수 있 습 니 다.
내 려 와 서 바로 실천 하 다.

    delegate void ClearCodedOutputStream(CodedOutputStream stream, byte[] buffer, int offset, int count);
    static ClearCodedOutputStream ResetCodedOutputStream;
    static CodedOutputStream codedOutputStream = new CodedOutputStream(new byte[10]);

    static unsafe void Encode(IMessage msg, byte[] buffer)
    {
      ResetCodedOutputStream(codedOutputStream, buffer, 0, buffer.Length);
      msg.WriteTo(codedOutputStream);
      codedOutputStream.Flush();
    }

    static Action<T, TValue> MakeSetter<T, TValue>(FieldInfo field)
    {
      DynamicMethod m = new DynamicMethod(
        "setter", typeof(void), new Type[] { typeof(T), typeof(TValue) }, typeof(Program));
      ILGenerator cg = m.GetILGenerator();

      cg.Emit(OpCodes.Ldarg_0);
      cg.Emit(OpCodes.Ldarg_1);
      cg.Emit(OpCodes.Stfld, field);
      cg.Emit(OpCodes.Ret);

      return (Action<T, TValue>)m.CreateDelegate(typeof(Action<T, TValue>));
    }

    static void Main(string[] args)
    {
      var bufferField = typeof(CodedOutputStream).GetField("buffer", BindingFlags.NonPublic | BindingFlags.Instance);
      var limitField = typeof(CodedOutputStream).GetField("limit", BindingFlags.NonPublic | BindingFlags.Instance);
      var positionField = typeof(CodedOutputStream).GetField("position", BindingFlags.NonPublic | BindingFlags.Instance);

      var setLimit = MakeSetter<CodedOutputStream, int>(limitField);
      var setPosition = MakeSetter<CodedOutputStream, int>(positionField);
      var setBuffer = MakeSetter<CodedOutputStream, byte[]>(bufferField);

      ResetCodedOutputStream = (stream, buffer, offset, length) => 
      {
        //this.buffer = buffer;
        //this.position = offset;
        //this.limit = offset + length;
        setBuffer(stream, buffer);
        setPosition(stream, offset);
        setLimit(stream, offset + length);
      };

      var buffer = new byte[msg.CalculateSize()];
      Encode(msg, buffer);
    }
이 인 스 턴 스 코드 에는 static 의 전역 Coded Output Stream 을 사 용 했 습 니 다.진정 으로 사용 할 때 스 레 드 안전 을 확보 해 야 합 니 다.
그래서 다음 문 제 는:
1.CodedOutput Stream 대상 스 레 드 의 안전 을 어떻게 보장 합 니까?
2.var buffer=new byte[msg.Calculate Size()];이것 도 아 껴.
이 두 문 제 는 독자 에 게 생각 하도록 남 겨 두 었 다.
Github:  http://github.com/egmkang
C\#Protobuf 가 0 분 배 된 메모리 의 직렬 화 를 어떻게 하 는 지 에 대한 자세 한 설명 은 여기까지 입 니 다.더 많은 관련 C\#Protobuf 직렬 화 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부탁드립니다!

좋은 웹페이지 즐겨찾기