В следующем коде выделенный ресурс (экземпляр 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.
Здравствуйте, _FRED_, Вы писали:
_FR>Будьте бдительны! Жаль, Object Initializer удобная и удачная конструкция, но не везде применима.
А я только недавно узнал про скрытую локальную переменную при инициализации Object Initializer'ом, подумал — вот как хорошо, если при инициализации исключение будет, то инициализируемая локальная останется null, как если бы в конструкторе исключение было, а оно вон какие эффекты даёт...
Здравствуйте, Пельмешко, Вы писали:
_FR>>Будьте бдительны! Жаль, Object Initializer удобная и удачная конструкция, но не везде применима.
П>А я только недавно узнал про скрытую локальную переменную при инициализации Object Initializer'ом, подумал — вот как хорошо, если при инициализации исключение будет, то инициализируемая локальная останется null, как если бы в конструкторе исключение было, а оно вон какие эффекты даёт...
Между прочим, в этих граблях виноват… ты Я их увидел, прочитав этот пост
Здравствуйте, _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");
}
}
А так как инициалайзеры призваны упростить создание конструкторов со множественными параметрами, этого следует ожидать.
Здравствуйте, 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.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, Пельмешко, Вы писали:
_FR>>>Будьте бдительны! Жаль, Object Initializer удобная и удачная конструкция, но не везде применима.
П>>А я только недавно узнал про скрытую локальную переменную при инициализации Object Initializer'ом, подумал — вот как хорошо, если при инициализации исключение будет, то инициализируемая локальная останется null, как если бы в конструкторе исключение было, а оно вон какие эффекты даёт...
_FR>Между прочим, в этих граблях виноват… ты Я их увидел, прочитав этот пост
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 в данной ситуации?
Здравствуйте, _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>то вызвавшему метод освобождать ничего не нужно
Здравствуйте, alexsoff, Вы писали:
A>То такое поведение вполне логично. Поля инициализируются в момент создания ресурса. Тем самым, если возникло исключение, то _FR>>то вызвавшему метод освобождать ничего не нужно
А кто должен освобождать? Сеттер свойства? А откуда он узнает, что он вызван из object initializer? Я думаю, что дизайн языка здесь не совсем продуман.
Здравствуйте, 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.
Здравствуйте, nikov, Вы писали:
A>>То такое поведение вполне логично. Поля инициализируются в момент создания ресурса. Тем самым, если возникло исключение, то _FR>>>то вызвавшему метод освобождать ничего не нужно
N>А кто должен освобождать? Сеттер свойства? А откуда он узнает, что он вызван из object initializer?
Конечно нет.
N>Я думаю, что дизайн языка здесь не совсем продуман.
Именно, но, ИМХО, не столько языка (того, что мы пишем), сколько реализации Object Initializer (того, что происходит в компиляторе).
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, nikov, Вы писали:
N>А кто должен освобождать? Сеттер свойства? А откуда он узнает, что он вызван из object initializer? Я думаю, что дизайн языка здесь не совсем продуман.
Так, стоп. Всмысле кто должен освобождать? сказано же в контексте инишиалайзера, думается что ресурсы еще не выделялись, это все равно, что вы создали бы параметры в конструкторе и внутри бы инициализировали свойста.
Откуда свойства знают, что они инициализируются в конструкторе?
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, alexsoff, Вы писали:
_FR>>>В следующем коде выделенный ресурс (экземпляр MyClass) не будет освобождён A>>Юзинг не будет вызван и в следующем коде:
_FR>Должен быть вызван Dispose()
точно вызовется? мои тесты показали вывод
Ctor
Catch
да и не должен вызываться это же эквивалент такого:
var x = new MyClass();
try{
x.Value=1;
}
finally{
x.Dispose();
}
Здравствуйте, cadet354, Вы писали:
_FR>>>>В следующем коде выделенный ресурс (экземпляр MyClass) не будет освобождён A>>>Юзинг не будет вызван и в следующем коде: _FR>>Должен быть вызван Dispose() C>точно вызовется? мои тесты показали вывод
Тесты чего? Покажи, что тестишь :о)) Оригинальный код или пример alexsoff?
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _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>а с появлением нового синтаксиса
Нужно хорошенько ознакомиться с ньюансами
Здравствуйте, _FRED_, Вы писали:
_FR>а с появлением нового синтаксиса, его (синтаксиса) использование может привести к проблемам и тут автор класса бессилен.
это не эквивалентный код, вот эквивалент
Здравствуйте, 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.
Здравствуйте, cadet354, Вы писали:
_FR>>а с появлением нового синтаксиса, его (синтаксиса) использование может привести к проблемам и тут автор класса бессилен. C>это не эквивалентный код, вот эквивалент