Задумал замутить производный класс от System.IO.Stream....
И реально не догоняю о чем (и чем) думал программер который мутил такую реализацию Close, Dispose в Stream
Скрытый текст
// System.IO.Stream
/// <summary>Закрывает текущий поток и отключает все ресурсы (например, сокеты и файловые дескрипторы), связанные с текущим потоком.</summary>
/// <filterpriority>1</filterpriority>public virtual void Close()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
// System.IO.Stream
/// <summary>Освобождает все ресурсы, используемые объектом <see cref="T:System.IO.Stream" />.</summary>public void Dispose()
{
this.Close();
}
// System.IO.Stream
/// <summary>Освобождает неуправляемые (а при необходимости и управляемые) ресурсы, используемые объектом <see cref="T:System.IO.Stream" />.</summary>
/// <param name="disposing">
/// Значение true позволяет освободить управляемые и неуправляемые ресурсы; значение false позволяет освободить только неуправляемые ресурсы.</param>protected virtual void Dispose(bool disposing)
{
if (disposing && this._asyncActiveEvent != null)
{
this._CloseAsyncActiveEvent(Interlocked.Decrement(ref this._asyncActiveCount));
}
}
Ну вот, черт, возьми и поменяй реализации Close и Dispose местами. Так, как это (фактически) сделано в System.IO.TextReader. И все будут счастливы.
Одним могут сделать Close/Dispose монописуальными.
Другие могут замутить так, что Close!=Dispose. То есть после Close еще можно вызвать Dispose, а вот после Dispose вызвать Close уже нельзя (ObjectDisposedException).
А в текущем виде этот Close — вот он даром не впился. Потому что нельзя узнать — Close был вызван явно или через Dispose
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
КД>Задумал замутить производный класс от System.IO.Stream....
Изначально не правильная идея.
КД>А в текущем виде этот Close — вот он даром не впился. Потому что нельзя узнать — Close был вызван явно или через Dispose
Почему???
Здравствуйте, Tom, Вы писали:
КД>>Задумал замутить производный класс от System.IO.Stream.... Tom>Изначально не правильная идея.
Просвети темных — что не правильно, и как правильно? КД>>А в текущем виде этот Close — вот он даром не впился. Потому что нельзя узнать — Close был вызван явно или через Dispose Tom>Почему???
А что — есть способ? Если есть, то я его не асилил.
Вообще, я решил забить на эти тонкости. Раз System.IO.Stream.Close это полный аналог его Dispose — то и черт с ними.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>А в текущем виде этот Close — вот он даром не впился. Потому что нельзя узнать — Close был вызван явно или через Dispose
Здравствуйте, Ikemefula, Вы писали:
КД>>А в текущем виде этот Close — вот он даром не впился. Потому что нельзя узнать — Close был вызван явно или через Dispose
I>А зачем тебе это знать ?
Чтобы после Close другие методы (кроме Close, Dispose) возвращали ошибку (InvalidOperationException) "Вызов такого-то метода невозможен, потому что объект потока был закрыт.". Кстати, у меня в закрытое состояние Stream может перейти и при вызове Close у родительского подключения.
А после Dispose все другие методы (кроме самого Dispose) возвращали ошибку (ObjectDisposedException) "Вызов такого-то метода невозможен, потому что объект потока был разрушен."
Сдается мне Я точно знаю, что чем точнее и подробнее буду сообщать о причинах отказа в обслуживании, тем проще будет осуществлять удаленную поддержку. Поэтому так и заморачиваюсь
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Чтобы после Close другие методы (кроме Close, Dispose) возвращали ошибку (InvalidOperationException) "Вызов такого-то метода невозможен, потому что объект потока был закрыт.". КД>А после Dispose все другие методы (кроме самого Dispose) возвращали ошибку (ObjectDisposedException) "Вызов такого-то метода невозможен, потому что объект потока был разрушен."
Заставлять различать извне и наделять Close и Dispose различным поведением — очень плохая идея.
Само по себе наличие Close — ошибка дизайна, но это не значит, что вокруг нужно разложить еще несколько граблей. Close должен быть эквивалентным Dispose.
КД>Кстати, у меня в закрытое состояние Stream может перейти и при вызове Close у родительского подключения.
Что такое "родительское подключение"?
Здравствуйте, HowardLovekraft, Вы писали:
HL>Заставлять различать извне и наделять Close и Dispose различным поведением — очень плохая идея. HL>(1) Само по себе наличие Close — ошибка дизайна, но это не значит, что вокруг нужно разложить еще несколько граблей. (2) Close должен быть эквивалентным Dispose.
(1) Вот о том и речь. Надо было делать Close обычным методом. Раз уж приспичило иметь такой метод. А не виртуальным. И всю логику закрытия потока предлагать реализовывать в Dispose(bool disposing).
(2) Это субъективное мнение смотрящего.
Лично я предпочитаю разделять управление ресурсом и управление объектом:
1. Close — закрывает ресурс.
2. Dispose — "убивает" объект.
Надо быть последовательными. Потому что у некоторых классов после Close объект остается в живых и позволяет с собой работать.
КД>>Кстати, у меня в закрытое состояние Stream может перейти и при вызове Close у родительского подключения. HL>Что такое "родительское подключение"?
А, ну да. Это подключение к базе данных, в рамках которого был создан выше-обозначенный Stream.
Я делаю потомка System.IO.Stream аналогичного (internal) System.Data.SqlClient.SqlStream. В рамках своего ADO.NET провайдера.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>(1) Вот о том и речь. Надо было делать Close обычным методом.
Его не надо было делать вообще.
КД>(2) Это субъективное мнение смотрящего. КД>Лично я предпочитаю разделять управление ресурсом и управление объектом:
Вы, конечно, вправе предпочитать что угодно, но Close был задуман всего лишь как метод с более специфичным для предметной области наименованием, нежели Dispose.
Да, иделогически — это тупо синоним. В 99.9% случаев Close и Dispose эквивалентны. Как можно догадаться, исходя из этого большинство юзеров вашей библиотеки так же не будут делать различия между Close и Dispose.
КД>Потому что у некоторых классов после Close объект остается в живых и позволяет с собой работать.
Сколько таких классов вы можете привести в качестве примера, не залезая в гугл?
У скольких из тех, что вы вспомнили, вы сходу сможете объяснить разницу в поведении?
Зачем брать пример с нескольких исключений (причем не факт, что для них это было удачное или хотя бы оправданное решение), если есть вполне определенное правило?
Здравствуйте, HowardLovekraft, Вы писали:
HL>Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>>(1) Вот о том и речь. Надо было делать Close обычным методом. HL>Его не надо было делать вообще.
Я же написал — если приспичило. А в самом первом сообщение я написал — "А в текущем виде этот Close — вот он даром не впился". И дело не в том, что он не нужен. А в том, что Stream.Dispose так реализован, что Stream.Close становится бессмысленным. Особенно забавляет виртуальность Close.
Бага, собственно говоря, заключается в том, что Dispose вызывает Close вместо Dispose(/*disposing*/true);
КД>>Потому что у некоторых классов после Close объект остается в живых и позволяет с собой работать. HL>Сколько таких классов вы можете привести в качестве примера, не залезая в гугл?
Зачем мне их вспоминать, если я такие уже реализовывал
Объекты, у которых есть Open. То есть после Close можно снова открыть.
Ну можно придумать еще класс без Open, но который после Close сохраняет некоторую статистику о проделанной работе и позволяет её получать. А после Dispose — объект переходит в режим "я разрушен" и отклоняет все вызовы.
HL>У скольких из тех, что вы вспомнили, вы сходу сможете объяснить разницу в поведении?
Это что — так сложно различать Close/Dispose?
В COM, к примеру, есть IUnknown::Release. И его почему-то не путают с Close-подобными методами в интерфейсе.
HL>Зачем брать пример с нескольких исключений (причем не факт, что для них это было удачное или хотя бы оправданное решение), если есть вполне определенное правило?
Вот это вопрос я не понял
Да и вообще я не понял — что конкретно вы пытаетесь мне объяснить? Ранее я уже написал — Раз System.IO.Stream.Close это полный аналог его Dispose — то и черт с ними.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Tom>>Изначально не правильная идея. КД>Просвети темных — что не правильно, и как правильно?
Самый правильный вариант это включение стрима а не наследование
КД>>>А в текущем виде этот Close — вот он даром не впился. Потому что нельзя узнать — Close был вызван явно или через Dispose Tom>>Почему???
КД>А что — есть способ? Если есть, то я его не асилил.
Способ чего?
КД>Вообще, я решил забить на эти тонкости. Раз System.IO.Stream.Close это полный аналог его Dispose — то и черт с ними.
Ты поясни что не так с Close и Dispose???
Здравствуйте, Tom, Вы писали:
Tom>>>Изначально не правильная идея. КД>>Просвети темных — что не правильно, и как правильно? Tom>Самый правильный вариант это включение стрима а не наследование
Вот мои пользователи и будут включать объекты моего потомка от System.IO.Stream. КД>>>>А в текущем виде этот Close — вот он даром не впился. Потому что нельзя узнать — Close был вызван явно или через Dispose Tom>>>Почему???
КД>>А что — есть способ? Если есть, то я его не асилил. Tom>Способ чего?
КД>>Вообще, я решил забить на эти тонкости. Раз System.IO.Stream.Close это полный аналог его Dispose — то и черт с ними. Tom>Ты поясни что не так с Close и Dispose???
Попробуй, что ли, прочитать сообщения в этой ветке. Вроде все уже разжевано.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
КД>Вот мои пользователи и будут включать объекты моего потомка от System.IO.Stream.
Ты сам можешь его включать, и прекрасно кстати решишь свою проблему этим...
Здравствуйте, Коваленко Дмитрий, Вы писали:
I>>А зачем тебе это знать ?
КД>Чтобы после Close другие методы (кроме Close, Dispose) возвращали ошибку (InvalidOperationException) "Вызов такого-то метода невозможен, потому что объект потока был закрыт.". Кстати, у меня в закрытое состояние Stream может перейти и при вызове Close у родительского подключения.
КД>А после Dispose все другие методы (кроме самого Dispose) возвращали ошибку (ObjectDisposedException) "Вызов такого-то метода невозможен, потому что объект потока был разрушен."
КД>Сдается мне Я точно знаю, что чем точнее и подробнее буду сообщать о причинах отказа в обслуживании, тем проще будет осуществлять удаленную поддержку. Поэтому так и заморачиваюсь
У тебя же Close и Dispose виртуальные, возьми да переопредели их. Но мне шота кажется что ты лишнее делаешь.
Здравствуйте, Ikemefula, Вы писали:
I>У тебя же Close и Dispose виртуальные, возьми да переопредели их.
А вот что-то не получается Dispose переопределить. Наверное потому что System.IO.Stream.Dispose фактически реализован как "sealed"
// System.IO.Stream
/// <summary>Освобождает все ресурсы, используемые объектом <see cref="T:System.IO.Stream" />.</summary>public/*нет тут virtual*/void Dispose()
{
this.Close();
}
И в результате на мой
public override void Dispose()
{
this.Dispose(true);
}
Вылазит такая ошибка:
Ошибка 1 "xxxxxxxx.Dispose()" : невозможно переопределить наследуемый член "System.IO.Stream.Dispose()", так как он не помечен как виртуальный (virtual), абстрактный (abstract) или переопределяющий (override)
I>Но мне шота кажется что ты лишнее делаешь.
Дык. Причем очень много лишнего
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Зачем мне их вспоминать, если я такие уже реализовывал
Соболезную, однако речь не о вашем коде, а о чем-нибудь более распостраненном.
КД>Объекты, у которых есть Open. То есть после Close можно снова открыть.
Зачем, если можно повторно создать? Что экономим?
КД>Ну можно придумать еще класс без Open, но который после Close сохраняет некоторую статистику о проделанной работе и позволяет её получать.
Сферическое в ваккуме придумывать не надо.
КД>Это что — так сложно различать Close/Dispose?
Да. Причину я указал — в подавляющем большинстве случаев Close и Dispose — синонимы.
КД>В COM, к примеру, есть IUnknown::Release. И его почему-то не путают с Close-подобными методами в интерфейсе.
В COM-е с клиентской стороны не ковырялся лет 8, возразить ничего не могу.
КД>Да и вообще я не понял — что конкретно вы пытаетесь мне объяснить?
Не нужно делать типы, реализующие IDisposable, с различным поведением Close и Dispose.
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>А вот что-то не получается Dispose переопределить. Наверное потому что System.IO.Stream.Dispose фактически реализован как "sealed"
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Лично я предпочитаю разделять управление ресурсом и управление объектом: КД>1. Close — закрывает ресурс. КД>2. Dispose — "убивает" объект.
Dispose никого не убивает, он только освобождает неуправляемые ресурсы.