У меня есть много подобных классов, и я рекомендую сделать класс закрытым, когда это возможно. IDisposable
+ наследование может работать, но в 99% случаев оно вам не нужно - и с ним легко ошибаться.
Если вы не пишете общедоступный API-интерфейс (в этом случае приятно разрешить людям реализовывать ваш код, как они хотят - т.е. использовать IDisposable
), вам не нужно его поддерживать.
просто сделай:
public sealed class Foo : IDisposable
{
private StreamWriter _Writer;
public Foo(string path)
{
FileStream fileWrite = File.Open (path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
try {
_Writer = new StreamWriter (fileWrite, new ASCIIEncoding());
} catch {
fileWrite.Dispose();
throw;
}
}
public void Dispose()
{
_Writer.Dispose();
}
}
Обратите внимание на попытку ... поймать; технически конструктор StreamWriter
может вызвать исключение, и в этом случае он никогда не станет владельцем FileStream
, и вы должны утилизировать его самостоятельно.
Если вы действительно используете много IDisposable
с, подумайте над тем, чтобы поместить этот код в C ++ / CLI: это делает весь этот шаблонный код для вас (он прозрачно использует соответствующую технологию детерминированного уничтожения как для собственных, так и для управляемых объектов).
В Википедии есть достойный пример IDisposable для C ++ (действительно, если у вас много IDisposable, C ++ на самом деле намного проще, чем C #):
Википедия: C ++ / CLI Финализаторы и автоматические переменные .
Например, реализация «безопасного» одноразового контейнера в C ++ / CLI выглядит следующим образом ...
public ref class MyDisposableContainer
{
auto_handle<IDisposable> kidObj;
auto_handle<IDisposable> kidObj2;
public:
MyDisposableContainer(IDisposable^ a,IDisposable^ b)
: kidObj(a), kidObj2(b)
{
Console::WriteLine("look ma, no destructor!");
}
};
Этот код будет корректно располагать kidObj и kidObj2 даже без добавления пользовательской реализации IDisposable, и он устойчив к исключениям в любой реализации Dispose (не то, что это должно произойти, но все же), и его легко поддерживать перед лицом многих других IDisposable
участников или родных ресурсов.
Не то, чтобы я был большим поклонником C ++ / CLI, но для сильно ресурсо-ориентированного кода у него легко получается C # beat, и он абсолютно блестяще взаимодействует как с управляемым, так и с нативным кодом - короче говоря, идеальный клейкий код; ). Я склонен писать 90% своего кода на C #, но использую C ++ / CLI для всех потребностей взаимодействия (особенно если вы хотите вызвать любую функцию win32 - MarshalAs и другие атрибуты взаимодействия повсеместно ужасны и совершенно непонятны).