【问题标题】:Get Encoding of BinaryReader/Writer?获取 BinaryReader/Writer 的编码?
【发布时间】:2015-04-03 16:15:32
【问题描述】:

.NET BinaryReader/BinaryWriter 类可以通过指定一个Encoding 来构造,以用于与String 相关的操作。

我正在使用扩展方法实现自定义字符串格式,但仍会以尊重在实例化 BinaryReader/Writer 时指定的 Encoding 的方式实现它们。

似乎没有办法从读取器/写入器检索编码,即使从他们的类继承也是如此。我只能从他们那里继承来通过重新创建他们的所有构造函数来拦截传递的编码。我查看了.NET source code,它仅用于实例化解码器类(在BinaryReader 的情况下),但我也无法访问该类。

我会输给这些课程的缺点吗?我可以通过反射入侵它们吗?

【问题讨论】:

  • 好的,你是对的。不过,WriteString 方法似乎明确忽略了它(根据 MSDN)。
  • 如果在您的场景中子类化和拦截构造函数中的编码甚至是远程可行的,我更喜欢它而不是潜在的不稳定反射黑客。 (我什至不确定这是否可能,因为我在 Decoder 类中没有看到任何 Encoding 引用。)
  • 你能解释一下为什么你的扩展方法需要自己操作 BinaryReader/BinaryWriter 吗? ReadString/WriteString 方法应该翻译编码,所以如果你的扩展方法对传入和传出这些方法的字符串进行操作,在我看来你不必担心吗?
  • 这些类的设计假设您不能不知道这一点。因为创建阅读器或编写器的是您的代码,而不是框架的代码。也许这个假设不正确,但我们没有很多 SO 用户要求解决方法。不要丢失您需要的信息。
  • @DebugErr 也许与其做扩展方法,不如为 BinaryReader/BinaryWriter 编写一个封装附加逻辑的包装类,并使用该类代替?

标签: c# .net binaryreader binarywriter


【解决方案1】:

查看source code for BinaryReader,看到构造函数定义如下:

    public BinaryReader(Stream input, Encoding encoding, bool leaveOpen) {
        if (input==null) {
            throw new ArgumentNullException("input");
        }
        if (encoding==null) {
            throw new ArgumentNullException("encoding");
        }
        if (!input.CanRead)
            throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotReadable"));
        Contract.EndContractBlock();
        m_stream = input;
        m_decoder = encoding.GetDecoder();
        m_maxCharsSize = encoding.GetMaxCharCount(MaxCharBytesSize);
        int minBufferSize = encoding.GetMaxByteCount(1);  // max bytes per one char
        if (minBufferSize < 16) 
            minBufferSize = 16;
        m_buffer = new byte[minBufferSize];
        // m_charBuffer and m_charBytes will be left null.

        // For Encodings that always use 2 bytes per char (or more), 
        // special case them here to make Read() & Peek() faster.
        m_2BytesPerChar = encoding is UnicodeEncoding;
        // check if BinaryReader is based on MemoryStream, and keep this for it's life
        // we cannot use "as" operator, since derived classes are not allowed
        m_isMemoryStream = (m_stream.GetType() == typeof(MemoryStream));
        m_leaveOpen = leaveOpen;

        Contract.Assert(m_decoder!=null, "[BinaryReader.ctor]m_decoder!=null");
    }

所以看起来编码本身实际上并没有保留在任何地方。该类仅存储从编码派生的解码器。 m_decoder在类中定义如下:

    private Decoder  m_decoder;

您无法访问私有变量。在类的其余部分中搜索该变量表明它在内部的一些地方使用,但从未返回,所以我认为你不能在派生类的任何地方访问它而不做某种疯狂的反射/反汇编事情.必须将其定义为 protected 才能访问它。对不起。

编辑:

几乎可以肯定有比使用反射访问私有m_decoder 变量更好的方法来解决您的问题。即使您这样做了,它也可能无法为您提供编码,正如您在 cmets 中所指出的那样。但是,如果您仍然想这样做,请参阅this StackOverflow answer on how to access private members with reflection

【讨论】:

  • 另外,我认为不可能从解码器中取回编码,至少从我在滚动源代码时读到的内容来看是不可能的。
【解决方案2】:

如果在您的场景中子类化和拦截构造函数中的编码甚至是远程可行的,我更喜欢它而不是潜在的不稳定反射黑客。

但是,如果你出于某种原因必须走反射路线,这里有一些我从the BinaryReader source code you referenced找到的指针:

【讨论】:

  • 我采用了构造方法。幸运的是,他们只有 3 个公共构造函数。对于未指定编码的默认情况,请务必记住 new UTF8Encoding()
猜你喜欢
  • 2019-03-06
  • 2015-10-23
  • 1970-01-01
  • 2015-01-04
  • 2013-10-12
  • 2022-11-13
  • 1970-01-01
  • 2014-02-07
  • 1970-01-01
相关资源
最近更新 更多