获取BinaryReader/Writer的编码方式?

10

.NET的BinaryReader/BinaryWriter类可以在构造时使用指定的Encoding进行String相关操作。

我正在使用扩展方法实现自定义字符串格式,但是我希望它们能够以一种符合在实例化BinaryReader/Writer时指定的Encoding的方式来实现。

似乎没有办法从阅读器/编写器中检索编码,即使从它们的类继承。我只能从它们继承,并重新创建所有构造函数来拦截传递的编码。我查看了.NET源代码,它仅用于实例化解码器类(在BinaryReader的情况下),但我也无法访问它。

我在这些类中存在短板吗? 我可以通过反射入侵到它们中吗?


好的,你是正确的。不过 WriteString 方法似乎会明确忽略它(根据 MSDN)。 - H H
1
如果在构造函数中进行子类化和拦截编码甚至在您的情况下是可行的,我更喜欢它,而不是潜在不稳定的反射黑客。 (我不确定是否可能,因为我没有在解码器类中看到任何编码引用。) - nodots
你能解释一下为什么你的扩展方法需要在BinaryReader/BinaryWriter本身上操作吗?ReadString/WriteString方法应该翻译编码,所以如果你的扩展方法在这些方法中输入和输出的字符串上操作,那么似乎你就不必担心它了? - Joshua Carmody
3
这些课程的设计基于这样的假设,即您不可能不知道这一点。因为创建读取器或写入器的是您的代码而非框架的代码。也许这个假设并不正确,但我们并没有很多的SO用户寻求解决方法。不要丢失您所需的信息。 - Hans Passant
3
@DebugErr 或许不妨写一个封装了额外逻辑的BinaryReader/BinaryWriter包装类,然后使用该类,而不是使用扩展方法? - Joshua Carmody
显示剩余3条评论
2个回答

5

查看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变量更好的解决方法。即使您这样做,也可能无法获得编码,如您在评论中所述。但是,如果您仍然想这样做,请参见此StackOverflow答案,了解如何使用反射访问私有成员

此外,我认为无法从解码器中获取编码方式,至少在我浏览源代码时没有找到相关信息。 - Ray
我不明白为什么它甚至需要编码。毕竟,BinaryReader 是用来读取字节的,对吗? - Nyerguds

3
如果在您的情况下,子类化并拦截构造函数中的编码甚至是可行的话,我更喜欢它,而不是潜在不稳定的反射黑客技巧。
然而,如果出于某种原因你必须走反射路线,这里有一些我从你引用的BinaryReader源代码中找到的指针:

1
我选择了构造函数的方法。幸运的是,它们只有3个公共构造函数。请确保记住new UTF8Encoding()用于没有指定编码的默认情况。 - Ray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接