Получить кодировку BinaryReader/Writer?

Сеть BinaryReader/BinaryWriter классы могут быть построены с указанием Encoding использовать для Stringсвязанные операции.

Я реализовывал пользовательские форматы строк с помощью методов расширения, но все же реализовывал их так, чтобы они уважали Encoding указывается при создании экземпляра BinaryReader/Writer,

Кажется, что нет способа извлечь кодировку из устройства чтения / записи, даже при наследовании от их класса. Я мог только унаследовать их, чтобы перехватить переданную кодировку, воссоздав все их конструкторы. Я посмотрел на исходный код.NET, и он используется только для создания экземпляра класса Decoder (в случае BinaryReader), но я тоже не могу получить к нему доступ.

Я проигрываю с недостатком в этих классах здесь? Могу ли я взломать их с отражением?

2 ответа

Решение

Если подклассы и перехват Encoding в конструкторах даже отдаленно возможны в вашем сценарии, я бы предпочел это вместо потенциально нестабильных взломов отражения.

Однако, если вы по какой-то причине должны пойти по пути отражения, вот несколько указателей, которые я нашел в исходном коде BinaryReader, на который вы ссылались:

Глядя на исходный код 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 переменная. И даже если вы это сделали, это может не дать вам кодировку, как вы отметили в комментариях. Однако, если вы все равно хотите это сделать, посмотрите ответ Stackru о том, как получить доступ к закрытым членам с помощью отражения.

Другие вопросы по тегам