2013-09-15 4 views
0

У меня есть класс MyClass, которому нужны данные из файла, который будет использоваться на протяжении всего запуска программы. Для чтения в данных у меня есть еще один класс OpenFileService, производный от IDisposable и использует BinaryReader читать все данные:BinaryReader throws NullReferenceException при удалении

internal class OpenFileService : IDisposable 
{ 
    #region disposing data 
    bool disposed = false; 

    public void Dispose() 
    { 
     if (!disposed) 
     { 
      Dispose(true); 
      GC.SuppressFinalize(this); 
      disposed = true; 
     } 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      br.Dispose(); 
     } 
    } 

    ~OpenFileService() 
    { 
     Dispose(false); 
    } 
    #endregion 

    internal event EventHandler ErrorInFileReadEventHandler; 
    internal event EventHandler SuccessfulFileReadEventHandler; 

    private BinaryReader br; 

    internal void OpenFile(object obj) 
    { 
     MyClass sender = obj as MyClass; 
     bool isWrongFormat = false; 

     try 
     { 
      br = new BinaryReader(File.Open((sender).fileName, FileMode.Open)); 
      //read in header from file. 
      if (//header shows wrong file format) 
      {  
       isWrongFormat = true; 
       throw new System.Exception(); 
      } 
      //read rest of file. 
      SuccessfulFileReadEventHandler(this,null); 
     } 
     catch 
     { 
      if (isWrongFormat) 
       MessageBox.Show("Wrong format."); 
      else 
       MessageBox.Show("Couldn't access."); 
      ErrorInFileReadEventHandler(this, null); 
      return; 
     } 
     finally 
     { 
      this.Dispose(); 
     } 
    } 
} 

И он используется как таковой:

class MyClass 
{ 
    internal filePath; //assuming it has already been determined 

    internal ImageData(string filePath) 
    { 
     this.filePath = filePath; 
     OpenFileService ofs = new OpenFileService(); 
     ofs.ErrorInFileReadEventHandler += new EventHandler(UnsuccessfulFileRead); 
     ofs.SuccessfulFileReadEventHandler += new EventHandler(SuccessfulFileRead); 
     Thread thread = new Thread(new ParameterizedThreadStart(ofs.OpenFile)); 
     thread.IsBackground = true; 
     thread.Start(this); 
    } 
} 

Теперь, когда файл формат является неправильным, и я сам создаю исключение в блоке try, все работает без проблем, но когда файл фактически не может быть доступен (например, с защитой от записи), br.Dispose(); создает NullReferenceException, и я не могу понять, почему. Я действительно урезал код до его простых вещей, надеюсь, он не слишком длинный.

Редактировать: Возможный ответ можно найти из принятого ответа here в качестве рекомендуемого ответа Microsoft.

+1

Может быть, у br остается значение null, потому что файл защищен от записи? – Jacob

+0

Вау ... Я действительно пропустил эту мысль. Замена 'br.Dispose();' с 'if (br! = Null) br.Dispose();' похоже, решит его ... Спасибо, много! Я не могу поверить, что не думал об этом. – phil13131

+0

u приветствуется. может случиться с кем угодно. – Jacob

ответ

1

вопрос может стать понятнее, если вы разделяете ваш файл открытой логики через две строки:

try 
{ 
    var fs = File.Open((sender).fileName, FileMode.Open); 
    br = new BinaryReader(fs); 
} 
finally 
{ 
    br.Dispose(); 
} 

При сбое File.Open вызова, исключение без ничего быть назначено br поля. Когда вы попытаетесь утилизировать его в блоке finally, все равно будет null, таким образом, ваше исключение.

Edit: Как я хотел бы предложить исправить эту проблему:

try 
{ 
    using (FileStream fs = File.Open(sender.fileName, FileMode.Open)) 
    using (BinaryReader br = new BinaryReader(fs)) 
    {   
     //read in header from file. 
     if (/*header shows wrong file format*/) 
     {  
      isWrongFormat = true; 
      MessageBox.Show("Wrong format."); 
      ErrorInFileReadEventHandler(this, null); 
     } 
     else 
     { 
      //read rest of file. 
      SuccessfulFileReadEventHandler(this, null); 
     } 
    } 
} 
catch 
{ 
    MessageBox.Show("Couldn't access."); 
    ErrorInFileReadEventHandler(this, null); 
} 

В процессе, я понижен ваш BinaryReader от поля к локальной переменной. Поскольку вы обращаетесь к нему только в рамках метода OpenFile (и удаляя его перед возвратом), нет необходимости в том, чтобы его ссылка сохранялась вне метода.

+0

Я принимаю этот ответ, потому что понял, что это была проблема после комментария к моему вопросу. Спасибо за ваш ответ, я изменю его. Мне не нужно удалять fs как неуправляемый ресурс? – phil13131

+0

В общем, вы должны избавиться от любого объекта 'IDisposable', который вы создаете. Однако обертки обработки файлов - это (неудачное) исключение. Метод 'Dispose' класса' BinaryReader' также закрывает любой поток, который вы передали его конструктору во время инициализации. Итак, короткий ответ - нет, вам не нужно распоряжаться файловым потоком до тех пор, пока вы уничтожаете «BinaryReader». – Douglas

+0

Хорошо, спасибо, у меня появилось ощущение, что Microsoft добавит путаное исключение из своих соглашений об утилизации. – phil13131

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