using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 27.11.09 11:38
Оценка: 314 (23)
В следующем коде выделенный ресурс (экземпляр MyClass) не будет освобождён
using System;

class Program
{
  static void Main() {
    try {
      using(var x = new MyClass { Value = 1, }) {
        // some work
      }//using
    } catch {
      Console.WriteLine("Catch");
    }//try
  }
}

class MyClass : IDisposable
{
  public MyClass() {
    Console.WriteLine("Ctor");
  }

  public object Value {
    get { return null; }

    set {
      Console.WriteLine("Set property value");
      throw new Exception();
    }
  }

  public void Dispose() {
    Console.WriteLine("Disposed");
  }
}

Будьте бдительны! Жаль, Object Initializer удобная и удачная конструкция, но не везде применима.
Help will always be given at Hogwarts to those who ask for it.
Re: using + Object Initializer = грабли
От: Пельмешко Россия blog
Дата: 27.11.09 12:07
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Будьте бдительны! Жаль, Object Initializer удобная и удачная конструкция, но не везде применима.


А я только недавно узнал про скрытую локальную переменную при инициализации Object Initializer'ом, подумал — вот как хорошо, если при инициализации исключение будет, то инициализируемая локальная останется null, как если бы в конструкторе исключение было, а оно вон какие эффекты даёт...
Re[2]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 27.11.09 12:18
Оценка:
Здравствуйте, Пельмешко, Вы писали:

_FR>>Будьте бдительны! Жаль, Object Initializer удобная и удачная конструкция, но не везде применима.


П>А я только недавно узнал про скрытую локальную переменную при инициализации Object Initializer'ом, подумал — вот как хорошо, если при инициализации исключение будет, то инициализируемая локальная останется null, как если бы в конструкторе исключение было, а оно вон какие эффекты даёт...


Между прочим, в этих граблях виноват… ты Я их увидел, прочитав этот пост
Автор: Пельмешко
Дата: 26.11.09
Help will always be given at Hogwarts to those who ask for it.
Re: using + Object Initializer = грабли
От: alexsoff Россия  
Дата: 27.11.09 12:24
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>В следующем коде выделенный ресурс (экземпляр MyClass) не будет освобождён

Юзинг не будет вызван и в следующем коде:

class Program
{
    static void Main()
    {
        try
        {
            using (var x = new MyClass())
            {
                
            }//using
        }
        catch(Exception ex)
        {
            Console.WriteLine("Catch");
        }//try

        Console.ReadKey();
    }
}

class MyClass : IDisposable
{
    public MyClass()
    {
        Console.WriteLine("Ctor");
        throw new Exception();    }

    public object Value
    {
        get { return null; }

        set
        {
            Console.WriteLine("Set property value");
            throw new Exception();
        }
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    /// <filterpriority>2</filterpriority>
    public void Dispose()
    {
        Console.WriteLine("Disposed");
    }

}

А так как инициалайзеры призваны упростить создание конструкторов со множественными параметрами, этого следует ожидать.
Re[2]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 27.11.09 12:30
Оценка: 7 (2)
Здравствуйте, alexsoff, Вы писали:

_FR>>В следующем коде выделенный ресурс (экземпляр MyClass) не будет освобождён

A>Юзинг не будет вызван и в следующем коде:

Должен быть вызван Dispose()

A>class MyClass : IDisposable
A>{
A>    public MyClass()
A>    {
A>        Console.WriteLine("Ctor");
A>        throw new Exception();    }

A>А так как инициалайзеры призваны упростить создание конструкторов со множественными параметрами, этого следует ожидать.

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

В случае же со свойством ресурс уже выделен корректно.
Help will always be given at Hogwarts to those who ask for it.
Re[3]: using + Object Initializer = грабли
От: Пельмешко Россия blog
Дата: 27.11.09 12:35
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, Пельмешко, Вы писали:


_FR>>>Будьте бдительны! Жаль, Object Initializer удобная и удачная конструкция, но не везде применима.


П>>А я только недавно узнал про скрытую локальную переменную при инициализации Object Initializer'ом, подумал — вот как хорошо, если при инициализации исключение будет, то инициализируемая локальная останется null, как если бы в конструкторе исключение было, а оно вон какие эффекты даёт...


_FR>Между прочим, в этих граблях виноват… ты Я их увидел, прочитав этот пост
Автор: Пельмешко
Дата: 26.11.09


Ыыыы
В F# сюрприз аналогичный:

type MyClass =
    
    new() = { } then printfn "Ctor"
    
    member x.Value
      with get() = null :> obj
      and set(_) = printfn "Set property value"
                   failwith "uups!"
    
    interface System.IDisposable with
      member x.Dispose() = printfn "Disposed"

let main() =
    try  use x = new MyClass(Value = box 1)
         () (* some work *)
    with _ -> printfn "Catch"

> main();;
Ctor
Set property value
Catch

Интересно, а как будет выглядеть правильно сгенерированный код для using в данной ситуации?
Re[3]: using + Object Initializer = грабли
От: alexsoff Россия  
Дата: 27.11.09 12:48
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Должен быть вызван Dispose()

Да, я это имел ввиду


_FR>Общепринятым соглашением (о правильно написанных классах) является то, что если метод выделения ресурса (в данном случае конструктор) завершился неудачей, то вызвавшему метод освобождать ничего не нужно.

Но если прочитать об инициалайзерах:
здесь


Object initializers let you assign values to any accessible fields or properties of an object at creation time without having to explicitly invoke a constructor.


То такое поведение вполне логично. Поля инициализируются в момент создания ресурса. Тем самым, если возникло исключение, то
_FR>то вызвавшему метод освобождать ничего не нужно
Re[4]: using + Object Initializer = грабли
От: nikov США http://www.linkedin.com/in/nikov
Дата: 27.11.09 12:59
Оценка:
Здравствуйте, alexsoff, Вы писали:

A>То такое поведение вполне логично. Поля инициализируются в момент создания ресурса. Тем самым, если возникло исключение, то

_FR>>то вызвавшему метод освобождать ничего не нужно

А кто должен освобождать? Сеттер свойства? А откуда он узнает, что он вызван из object initializer? Я думаю, что дизайн языка здесь не совсем продуман.
Re[4]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 27.11.09 13:00
Оценка: +2
Здравствуйте, alexsoff, Вы писали:

_FR>>Общепринятым соглашением (о правильно написанных классах) является то, что если метод выделения ресурса (в данном случае конструктор) завершился неудачей, то вызвавшему метод освобождать ничего не нужно.

A>Но если прочитать об инициалайзерах:
A>здесь

A>Object initializers let you assign values to any accessible fields or properties of an object at creation time without having to explicitly invoke a constructor.

A>То такое поведение вполне логично.

Что здесь значит "такое"?

A>Поля инициализируются в момент создания ресурса.


В том-то и дело, что нет! Object initializers создают видимость того, что "Поля инициализируются в момент создания ресурса", но по факту это различные (не атомарные) операции.

A>Тем самым, если возникло исключение, то

_FR>>то вызвавшему метод освобождать ничего не нужно

Вот ведь какое дело: во втором шарпе проблем не возникало:
using(Resource x = new Resource()) {
  x.Value = xxx;
}//using

а с появлением нового синтаксиса, его (синтаксиса) использование может привести к проблемам и тут автор класса бессилен.

То есть правильно, по идее должен генериться такой код, что "вызвавшему метод освобождать ничего не нужно", но этого не происходит. Тот программист, что не понимает, как устроен Object initializer, может легко пропустить такую тонкость.
Help will always be given at Hogwarts to those who ask for it.
Re[5]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 27.11.09 13:02
Оценка:
Здравствуйте, nikov, Вы писали:

A>>То такое поведение вполне логично. Поля инициализируются в момент создания ресурса. Тем самым, если возникло исключение, то

_FR>>>то вызвавшему метод освобождать ничего не нужно

N>А кто должен освобождать? Сеттер свойства? А откуда он узнает, что он вызван из object initializer?


Конечно нет.

N>Я думаю, что дизайн языка здесь не совсем продуман.


Именно, но, ИМХО, не столько языка (того, что мы пишем), сколько реализации Object Initializer (того, что происходит в компиляторе).
Help will always be given at Hogwarts to those who ask for it.
Re[5]: using + Object Initializer = грабли
От: alexsoff Россия  
Дата: 27.11.09 13:03
Оценка:
Здравствуйте, nikov, Вы писали:

N>А кто должен освобождать? Сеттер свойства? А откуда он узнает, что он вызван из object initializer? Я думаю, что дизайн языка здесь не совсем продуман.

Так, стоп. Всмысле кто должен освобождать? сказано же в контексте инишиалайзера, думается что ресурсы еще не выделялись, это все равно, что вы создали бы параметры в конструкторе и внутри бы инициализировали свойста.
Откуда свойства знают, что они инициализируются в конструкторе?
Re[3]: using + Object Initializer = грабли
От: cadet354 Россия
Дата: 27.11.09 13:09
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, alexsoff, Вы писали:


_FR>>>В следующем коде выделенный ресурс (экземпляр MyClass) не будет освобождён

A>>Юзинг не будет вызван и в следующем коде:

_FR>Должен быть вызван Dispose()

точно вызовется? мои тесты показали вывод

Ctor
Catch

да и не должен вызываться это же эквивалент такого:
var x = new MyClass();
try{
    x.Value=1;
}
finally{
    x.Dispose();
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1270>>
Re[4]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 27.11.09 13:15
Оценка:
Здравствуйте, cadet354, Вы писали:

_FR>>>>В следующем коде выделенный ресурс (экземпляр MyClass) не будет освобождён

A>>>Юзинг не будет вызван и в следующем коде:
_FR>>Должен быть вызван Dispose()
C>точно вызовется? мои тесты показали вывод

Тесты чего? Покажи, что тестишь :о)) Оригинальный код или пример alexsoff?
Help will always be given at Hogwarts to those who ask for it.
Re[4]: using + Object Initializer = грабли
От: Воронков Василий Россия  
Дата: 27.11.09 13:16
Оценка:
Здравствуйте, cadet354, Вы писали:

C>да и не должен вызываться это же эквивалент такого:


Диспоз должен быть вызван ручками в конструкторе.
Re[5]: using + Object Initializer = грабли
От: alexsoff Россия  
Дата: 27.11.09 13:16
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>В том-то и дело, что нет! Object initializers создают видимость того, но по факту это различные (не атомарные) операции.

Ну здрасти, я же Вам и ссылку в msdn и процитировал. Что msdn вводит в заблуждение?


Object initializers let you assign values to any accessible fields or properties of an object at creation time without having to explicitly invoke a constructor



_FR>а с появлением нового синтаксиса

Нужно хорошенько ознакомиться с ньюансами

PS: Извините за сорказм
Re[5]: using + Object Initializer = грабли
От: cadet354 Россия
Дата: 27.11.09 13:41
Оценка:
Здравствуйте, _FRED_, Вы писали:



_FR>Тесты чего? Покажи, что тестишь :о)) Оригинальный код или пример alexsoff?

#region

using System;

#endregion

namespace TestUsing
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            try
            {
                using (var x = new MyClass())
                {
                    x.Value = 1;
                    // some work
                } //using
            }
            catch
            {
                Console.WriteLine("Catch");
            } //try
            finally
            {
                Console.ReadLine();
            }
        }
    }


    internal class MyClass : IDisposable
    {
        public MyClass()
        {
            Console.WriteLine("Ctor");
            throw new Exception();
        }

        public object Value
        {
            get { return null; }

            set { Console.WriteLine("Set property value"); }
        }

        #region IDisposable Members

        public void Dispose()
        {
            Console.WriteLine("Disposed");
        }

        #endregion
    }
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1270>>
Re[5]: using + Object Initializer = грабли
От: cadet354 Россия
Дата: 27.11.09 13:47
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>а с появлением нового синтаксиса, его (синтаксиса) использование может привести к проблемам и тут автор класса бессилен.

это не эквивалентный код, вот эквивалент
using(Resource x = CreateNewResource()) {

}//using
Resource CreateNewResource(){
    Resource t=new Resource();
    t.Value=xxx;
    return t;
}

и совершенно логично что диспоза не будет
... << RSDN@Home 1.2.0 alpha 4 rev. 1270>>
Re[6]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 27.11.09 13:48
Оценка:
Здравствуйте, cadet354, Вы писали:

_FR>>Тесты чего? Покажи, что тестишь :о)) Оригинальный код или пример alexsoff?

C>                using (var x = new MyClass())
C>                {
C>                    x.Value = 1;
C>                    // some work
C>                } //using


И что в этом примере смущает? при возникновении исключения в точке выделения ресурса (в конструкторе) вызывать Dispose и не нужно, потому что считается, что ресурс не выделился я же ровно об этом в ответ и писал. Если что-то не ясно оказалось — спроси пожалуйста конкретнее.
Help will always be given at Hogwarts to those who ask for it.
Re[6]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 27.11.09 13:51
Оценка: +1
Здравствуйте, cadet354, Вы писали:

_FR>>а с появлением нового синтаксиса, его (синтаксиса) использование может привести к проблемам и тут автор класса бессилен.

C>это не эквивалентный код, вот эквивалент
C>using(Resource x = CreateNewResource()) {

C>}//using
C>Resource CreateNewResource(){
C>    Resource t=new Resource();
C>    t.Value=xxx;
C>    return t;
C>}

C>и совершенно логично что диспоза не будет

Здесь на лицо криво написанный метод выделения ресурса. Люди, заботящиеся о своей карме, делают так:
C>Resource CreateNewResource() {
C>  Resource t = new Resource();
    try {
C>    t.Value = xxx;
    } catch {
      t.Dispose();
      throw;
    }//try
C>  return t;
C>}

Теперь совершенно безопасно делать так:
C>using(Resource x = CreateNewResource()) {

C>}//using
Help will always be given at Hogwarts to those who ask for it.
Re[7]: using + Object Initializer = грабли
От: alexsoff Россия  
Дата: 27.11.09 14:01
Оценка:
Здравствуйте, _FRED_, Вы писали:
C>>Resource CreateNewResource() {
C>> Resource t = new Resource();
_FR> try {
C>> t.Value = xxx;
_FR> } catch {
_FR> t.Dispose();
_FR> throw;
_FR> }//try
Почему так правильно? А не так:


MyClass cl  = new MyClass();
        try
        {
            cl.Value = "111";
            
        }finally {
            cl.Dispose();
        }
Re[8]: using + Object Initializer = грабли
От: nikov США http://www.linkedin.com/in/nikov
Дата: 27.11.09 14:08
Оценка:
Здравствуйте, alexsoff, Вы писали:

A>Почему так правильно? А не так:



A>
A>MyClass cl  = new MyClass();
A>        try
A>        {
A>            cl.Value = "111";
            
A>        }finally {
A>            cl.Dispose();
A>        }
A>


Потому что finally выполняется даже если не было исключения.
Re[8]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 27.11.09 14:08
Оценка:
Здравствуйте, alexsoff, Вы писали:

[c#]
C>>>Resource CreateNewResource() {
C>>>  Resource t = new Resource();
_FR>>    try {
C>>>    t.Value = xxx;
_FR>>    } catch {
_FR>>      t.Dispose();
_FR>>      throw;
_FR>>    }//try

[/c#]
A>Почему так правильно? А не так:
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.
Re[9]: using + Object Initializer = грабли
От: alexsoff Россия  
Дата: 27.11.09 14:11
Оценка:
Здравствуйте, nikov, Вы писали:

finally {
            cl.Dispose();
        }


N>Потому что finally выполняется даже если не было исключения.

А что мы должны ресурсы освобождать, когда только возникает исключение?
Re[9]: using + Object Initializer = грабли
От: alexsoff Россия  
Дата: 27.11.09 14:13
Оценка:
Здравствуйте, _FRED_, Вы писали:
A>>}
_FR> return cl; // Бессмысленная [скорее всего] операция, потому что cl уже уничтожен.
Согласен бессмыслино, но мы же тут вроде разбираем аналоги using
Re[10]: using + Object Initializer = грабли
От: nikov США http://www.linkedin.com/in/nikov
Дата: 27.11.09 14:14
Оценка:
Здравствуйте, alexsoff, Вы писали:

N>>Потому что finally выполняется даже если не было исключения.

A>А что мы должны ресурсы освобождать, когда только возникает исключение?

В данном методе — да, так как это метод CreateNewResource для создания ресурса. Если ресурс успешно создан, то о его закрытии должен позаботиться вызывающий метод после того, как он завершит работу с ним.
Re[7]: using + Object Initializer = грабли
От: cadet354 Россия
Дата: 27.11.09 14:20
Оценка:
Здравствуйте, _FRED_, Вы писали:

смущает твой ответ:

A>Юзинг не будет вызван и в следующем коде:

Должен быть вызван Dispose()

A>class MyClass : IDisposable
A>{
A> public MyClass()
A> {
A> Console.WriteLine("Ctor");
A> throw new Exception(); }

... << RSDN@Home 1.2.0 alpha 4 rev. 1270>>
Re[7]: using + Object Initializer = грабли
От: cadet354 Россия
Дата: 27.11.09 14:20
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, cadet354, Вы писали:


_FR>>>а с появлением нового синтаксиса, его (синтаксиса) использование может привести к проблемам и тут автор класса бессилен.

C>>это не эквивалентный код, вот эквивалент
_FR>
C>>using(Resource x = CreateNewResource()) {

C>>}//using
C>>Resource CreateNewResource(){
C>>    Resource t=new Resource();
C>>    t.Value=xxx;
C>>    return t;
C>>}
_FR>

C>>и совершенно логично что диспоза не будет

_FR>Здесь на лицо криво написанный метод выделения ресурса. Люди, заботящиеся о своей карме, делают так:

я про это и не спорю,
мой пример показал во что разворачивается использование object initialization в using,
и следовательно не понятно твое удивление (что не будет вызван dispose)
по этому поводу.
... << RSDN@Home 1.2.0 alpha 4 rev. 1270>>
Re[8]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 27.11.09 14:22
Оценка:
Здравствуйте, cadet354, Вы писали:

C>смущает твой ответ:

C>[q]
A>>Юзинг не будет вызван и в следующем коде:

C>Должен быть вызван Dispose()


Мой ответ про "Должен быть вызван Dispose()" никакого отношения к коду ниже не имеет, потому что лишь уточняет фразу "Юзинг не будет вызван и в следующем коде:".
Help will always be given at Hogwarts to those who ask for it.
Re[7]: using + Object Initializer = грабли
От: TK Лес кывт.рф
Дата: 28.11.09 15:08
Оценка: +1
Здравствуйте, _FRED_, Вы писали:

_FR>Здесь на лицо криво написанный метод выделения ресурса. Люди, заботящиеся о своей карме, делают так:


Это костыли, а не забота о карме. Те кто заботится о карме не кидают исключений из сеттеров.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[8]: using + Object Initializer = грабли
От: alexsoff Россия  
Дата: 28.11.09 18:07
Оценка: +1
Здравствуйте, TK, Вы писали:

TK>Это костыли, а не забота о карме. Те кто заботится о карме не кидают исключений из сеттеров.

+1
Я если хочу кинуть исключение, при изменении проперти, тогда я это оборачиваю в set метод.
Re[8]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 28.11.09 19:23
Оценка: +2
Здравствуйте, 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.
Re[9]: using + Object Initializer = грабли
От: TK Лес кывт.рф
Дата: 28.11.09 20:32
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Далее. В том моём примере внутри try может быть не только установка свойств, а несколько различных операций, которые при любых "кармических взглядах" имеют право сделать throw, так что "паттерн" приведённый в том моём сообщении не "костыль". Любопытно было бы взглянуть на другую реализацию той же задачи


Предложенный "паттерн" имеет смысл только для использования с "унаследованным" кодом — выглядит он ужасно. Другая реализация задачи может быть такой:

using (var container = new Container())
{
   var resource = container.Resolve<Resource>(parameters)
   resource(...);
}
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[10]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 28.11.09 20:52
Оценка:
Здравствуйте, 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.
Re: using + Object Initializer = грабли
От: alexsoff Россия  
Дата: 29.11.09 07:53
Оценка:
Здравствуйте, _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.
И получается, что такое поведение вполне закономерно.
Или у Вас другое мнение?
Re[2]: using + Object Initializer = грабли
От: desco США http://v2matveev.blogspot.com
Дата: 29.11.09 08:50
Оценка: +1
Здравствуйте, alexsoff, Вы писали:

<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 дело просто не дойдет.
Re[2]: using + Object Initializer = грабли
От: _FRED_ Черногория
Дата: 29.11.09 09:10
Оценка: +2
Здравствуйте, 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.
Re[11]: using + Object Initializer = грабли
От: TK Лес кывт.рф
Дата: 29.11.09 19:03
Оценка: +1
Здравствуйте, _FRED_, Вы писали:

TK>>Предложенный "паттерн" имеет смысл только для использования с "унаследованным" кодом — выглядит он ужасно.

_FR>Что именно не нравится?

Не нравится идея с "передачей владения" объектом.

_FR>И чем это будет лучше? И, заодно, можешь примерно показать код метода Resolve<>? В частности, неужели в коде этого метода можно обойтись без единого try? Тогда в чём принципиальная разница с моим примером?


Инициализация объекта может идти в два этапа — на первом этепе создается экземпляр и он добавляется в контейнер. На втором этапе выполняется "инициализация" свойств/конфигурирование объекта. Возникновение исключений на любом этапе — проблема контейнера. Конечный пользователь несет ответственность только за "освобождение" контейнера.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.