A>MyClass cl = new MyClass();
A> try
A> {
A> cl.Value = "111";
A> }finally {
A> cl.Dispose();
A> }
Так тоже правильно, но задача другая. Из функции CreateNewResource() нужно вернуть готовый к использованию ресурс, поэтому Dispose() там вызывается только в случае ошибки. А тут если ниже дописать:
A>MyClass cl = new MyClass();
A>try
A>{
A> cl.Value = "111";
A>} finally {
A> cl.Dispose();
A>}
return cl; // Бессмысленная [скорее всего] операция, потому что cl уже уничтожен.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали: A>>} _FR> return cl; // Бессмысленная [скорее всего] операция, потому что cl уже уничтожен.
Согласен бессмыслино, но мы же тут вроде разбираем аналоги using
Здравствуйте, alexsoff, Вы писали:
N>>Потому что finally выполняется даже если не было исключения. A>А что мы должны ресурсы освобождать, когда только возникает исключение?
В данном методе — да, так как это метод CreateNewResource для создания ресурса. Если ресурс успешно создан, то о его закрытии должен позаботиться вызывающий метод после того, как он завершит работу с ним.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, cadet354, Вы писали:
_FR>>>а с появлением нового синтаксиса, его (синтаксиса) использование может привести к проблемам и тут автор класса бессилен. C>>это не эквивалентный код, вот эквивалент _FR>
C>>и совершенно логично что диспоза не будет
_FR>Здесь на лицо криво написанный метод выделения ресурса. Люди, заботящиеся о своей карме, делают так:
я про это и не спорю,
мой пример показал во что разворачивается использование object initialization в using,
и следовательно не понятно твое удивление (что не будет вызван dispose)
по этому поводу.
Здравствуйте, cadet354, Вы писали:
C>смущает твой ответ: C>[q] A>>Юзинг не будет вызван и в следующем коде:
C>Должен быть вызван Dispose()
Мой ответ про "Должен быть вызван Dispose()" никакого отношения к коду ниже не имеет, потому что лишь уточняет фразу "Юзинг не будет вызван и в следующем коде:".
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, TK, Вы писали:
TK>Это костыли, а не забота о карме. Те кто заботится о карме не кидают исключений из сеттеров.
+1
Я если хочу кинуть исключение, при изменении проперти, тогда я это оборачиваю в set метод.
Здравствуйте, TK, Вы писали:
_FR>>Здесь на лицо криво написанный метод выделения ресурса. Люди, заботящиеся о своей карме, делают так: TK>Это костыли, а не забота о карме. Те кто заботится о карме не кидают исключений из сеттеров.
Из геттеров.
Avoid throwing exceptions from property getters.
(Property Design) Да и то "Avoid", а не строгое "Do not". Там же:
Do preserve the previous value if a property setter throws an exception.
что так же косвенно (но явно) говорит о возможности(или, вернее, законности) возникновения исключения в сеттере.
Если оторваться от текущей задачи, то при вызове сеттера можно легко натолкнуться на исключение: например, возбуждается event PropertyChanged и в одном из обработчиков срабатывает исключение. Формально — исключение возникло и в сеттере, так что обеспечить exception free сеттеров очень сложно. Второе: есть FileStream.Position Property
Конечно, это не плохой дизайн, когда все операции, которые могут привести к исключительной ситуации объявлены как методы, а не как свойства. Но многие операции очень привычно "оборачивать" именно свойствами с возможностью throw в сеттере.
Далее. В том моём примере внутри try может быть не только установка свойств, а несколько различных операций, которые при любых "кармических взглядах" имеют право сделать throw, так что "паттерн" приведённый в том моём сообщении не "костыль". Любопытно было бы взглянуть на другую реализацию той же задачи
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Далее. В том моём примере внутри try может быть не только установка свойств, а несколько различных операций, которые при любых "кармических взглядах" имеют право сделать throw, так что "паттерн" приведённый в том моём сообщении не "костыль". Любопытно было бы взглянуть на другую реализацию той же задачи
Предложенный "паттерн" имеет смысл только для использования с "унаследованным" кодом — выглядит он ужасно. Другая реализация задачи может быть такой:
using (var container = new Container())
{
var resource = container.Resolve<Resource>(parameters)
resource(...);
}
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, TK, Вы писали:
_FR>>Далее. В том моём примере внутри try может быть не только установка свойств, а несколько различных операций, которые при любых "кармических взглядах" имеют право сделать throw, так что "паттерн" приведённый в том моём сообщении не "костыль". Любопытно было бы взглянуть на другую реализацию той же задачи
TK>Предложенный "паттерн" имеет смысл только для использования с "унаследованным" кодом — выглядит он ужасно.
Что именно не нравится?
TK>Другая реализация задачи может быть такой:
TK>using (var container = new Container())
TK>{
TK> var resource = container.Resolve<Resource>(parameters)
TK> resource(...);
TK>}
И чем это будет лучше? И, заодно, можешь примерно показать код метода Resolve<>? В частности, неужели в коде этого метода можно обойтись без единого try? Тогда в чём принципиальная разница с моим примером?
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали: _FR>Будьте бдительны! Жаль, Object Initializer удобная и удачная конструкция, но не везде применима.
Нашел время поэксперементировать.
сделал следующий финт:
class Program
{
static void Main(string[] args)
{
try {
using ( var mc = new MyClass().DoSomething() ) {
Console.WriteLine( "Inside using" );
}
} catch ( Exception ex ) {
Console.WriteLine( "Inside catch" );
} //catch
Console.ReadKey();
}
}
public class MyClass :IDisposable
{
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Object" /> class.
/// </summary>public MyClass()
{
Console.WriteLine( "Default constructor" );
filed1 = "Default value";
}
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Object" /> class.
/// </summary>public MyClass(string val)
{
filed1 = val;
}
public MyClass DoSomething()
{
throw new Exception();
Console.WriteLine( "DoSomething" );
return this;
}
#region Implementation of IDisposable
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>public void Dispose()
{
Console.WriteLine( "Disposed: field = " + filed1 );
}
#endregion
private string filed1 = string.Empty;
public string Filed1
{
get { return filed1; }
set {
filed1 = value;
throw new Exception();
}
}
}
Результат аналогичный! Dispose не вызвался.
Default constructor
Inside catch
Это меня навело на мыcли, что using просто транслируется в try finnaly.
И получается, что такое поведение вполне закономерно.
Или у Вас другое мнение?
<skipped/>
A>Результат аналогичный! Dispose не вызвался. A>
A>Default constructor
A>Inside catch
В спецификации четко описано, во что транслируется using
A using statement of the form
using (ResourceType resource = expression) statement
corresponds to one of two possible expansions. When ResourceType is a value type, the expansion is
{
ResourceType resource = expression;
try {
statement;
}
finally {
((IDisposable)resource).Dispose();
}
}
Otherwise, when ResourceType is a reference type, the expansion is
{
ResourceType resource = expression;
try {
statement;
}
finally {
if (resource != null) ((IDisposable)resource).Dispose();
}
}
видно, что захват ресурса происходит за рамками блока try. Соответственно, если при захвате было выброшено исключение, то до Dispose дело просто не дойдет.
Здравствуйте, alexsoff, Вы писали:
_FR>>Будьте бдительны! Жаль, Object Initializer удобная и удачная конструкция, но не везде применима. A>Нашел время поэксперементировать. A>сделал следующий финт:
A> using ( var mc = new MyClass().DoSomething() ) {
A>Результат аналогичный! Dispose не вызвался.
В данном случае синтаксис не оставляет сомнений в том, что using должен сработать над результатом .DoSomething(). В моём примере данный вывод не так очевиден.
A>Это меня навело на мыcли, что using просто транслируется в try finnaly.
Это знать, как бы, необходимо — в любой книжке про это написано
A>И получается, что такое поведение вполне закономерно.
С тем, что закономерно — конечно согласен. Внимание же стоит обратить на то, что в некоторых случаях "такое поведение" не вполне очевидно.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
TK>>Предложенный "паттерн" имеет смысл только для использования с "унаследованным" кодом — выглядит он ужасно. _FR>Что именно не нравится?
Не нравится идея с "передачей владения" объектом.
_FR>И чем это будет лучше? И, заодно, можешь примерно показать код метода Resolve<>? В частности, неужели в коде этого метода можно обойтись без единого try? Тогда в чём принципиальная разница с моим примером?
Инициализация объекта может идти в два этапа — на первом этепе создается экземпляр и он добавляется в контейнер. На втором этапе выполняется "инициализация" свойств/конфигурирование объекта. Возникновение исключений на любом этапе — проблема контейнера. Конечный пользователь несет ответственность только за "освобождение" контейнера.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.