2010-02-11 1 views
5

Рассматривая этот вопрос, который Джон отлично справился с ответом ... 'How to read a text file reversly with iterator'. И был аналогичный вопрос, в котором я ответил с помощью указателей hocus pocus .. '.net is there a way to read a text file from bottom to top' до того, как он закрылся.Почему вы не можете использовать небезопасное ключевое слово в контексте итератора?

Теперь я решил попытаться решить эту проблему с помощью указателей, по краям ...

 
public class ReadChar : IEnumerable<char> 
{ 
    private Stream _strm = null; 
    private string _str = string.Empty; 
    public ReadChar(string s) 
    { 
     this._str = s; 
    } 
    public ReadChar(Stream strm) 
    { 
     this._strm = strm; 
    } 
    public IEnumerator<char> GetEnumerator() 
    { 
     if (this._strm != null && this._strm.CanRead && this._strm.CanSeek) 
     { 
      return ReverseReadStream(); 
     } 
     if (this._str.Length > 0) 
     { 
      return ReverseRead(); 
     } 
     return null; 
    } 

    private IEnumerator<char> ReverseReadStream() 
    { 
     long lIndex = this._strm.Length; 
     while (lIndex != 0 && this._strm.Position != 0) 
     { 
      this._strm.Seek(lIndex--, SeekOrigin.End); 
      int nByte = this._strm.ReadByte(); 
      yield return (char)nByte; 
     } 
    } 

    private IEnumerator<char> ReverseRead() 
    { 
     unsafe 
     { 
      fixed (char* beg = this._str) 
      { 
       char* p = beg + this._str.Length; 
       while (p-- != beg) 
       { 
        yield return *p; 
       } 
      } 
     } 
    } 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

, но обнаружил, что C# компилятор не может справиться с этим, используя эту реализацию, но был опустошен, когда компилятор с # отказался с CS1629 ошибки - «небезопасный код не может появиться в итераторы»

Почему это так?

+0

Подумайте о том, как 'yield return' работает под капотом. –

ответ

1

Это просто часть C# спецификации:

26.1 Блоки итераторов ... Это ошибка времени компиляции итератор блок содержит небезопасный контекст (§27.1). Блок итератора всегда определяет безопасный контекст, даже если его объявление вложено в небезопасный контекст.

Предположительно, код, который генерируется компилятором, должен поддаваться проверке, чтобы его не маркировали «небезопасным». Если вы хотите использовать указатели, вам придется реализовать IEnumerator самостоятельно.

+0

Спасибо за ваш ответ, но, безусловно, использование фиксированного ключевого слова гарантировано, что вы находитесь в пределах границ ... ??? например, вы вряд ли собираетесь топтать что-то, что не принадлежит вашему коду ... и это только для чтения, поэтому ... – t0mm13b

+0

@ tommieb75: Неверно, есть непроверяемые побочные эффекты с помощью указателей. О, Эрик Липперт обсуждает это ... прочь читать! – codekaizen

+0

Спасибо! ;) Я читаю его тоже и обдумываю об этом ... – t0mm13b

6

То, что я хочу знать, почему вы должны использовать указатели для этого вообще. Почему бы просто не сказать:

private IEnumerator<char> ReverseRead() 
{ 
    int len = _str.Length; 
    for(int i = 0; i < len; ++i) 
     yield return _str[len - i - 1]; 
} 

Какая неотразимая выгода от возиться с указателями?

Смежные вопросы