Конструкторы в .NET
От: Воронков Василий Россия  
Дата: 29.05.05 00:33
Оценка:
Возьмем два примера:

public abstract class Bar
{
    protected Bar()
    {
        //происходит виртуальный вызов, 
        //хотя код в конструкторе Foo еще не выполнен.
        Initialize();
    }
    
    protected virtual void Initialize()
    {
    
    }
}


public class Foo : Bar
{
    public Foo()
    {
    
    }
    
    
    protected override void Initialize()
    {
    
    }
}


и

public sealed class Foo
{
    private Foo()
    {
        Instance.Invoke();//NullReferenceException
    }
    
    public void Invoke()
    {
    
    }

    public readonly static Foo Instance = new Foo();
}


Существует ли какая-нибудь возможность логики связать между собой два этих поведения?
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Re: Конструкторы в .NET
От: 0Z Россия http://www.ucca.ru
Дата: 29.05.05 06:43
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

В этой строчке кода:
ВВ> public readonly static Foo Instance = new Foo();

вызывается конструктор:
ВВ> private Foo()
ВВ> {
ВВ> Instance.Invoke();//NullReferenceException
ВВ> }

А т.к. в этот момент времени Instance еще не проинициализирована, то получаем NullReferenceException.

И еще, нельзя из нестатической функции использовать статические члены класса (вроде так в спецификации написано).
MCSD.NET << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[2]: Конструкторы в .NET
От: Igor Sukhov  
Дата: 29.05.05 09:53
Оценка:
Здравствуйте, 0Z, Вы писали:

0Z>И еще, нельзя из нестатической функции использовать статические члены класса (вроде так в спецификации написано).


ты чего-то путаешь.
http://rsdn.org/File/76/Logo.gif * thriving in a production environment *
Re: Конструкторы в .NET
От: TK Лес кывт.рф
Дата: 29.05.05 10:13
Оценка:
Hello, "Воронков Василий"
>
> public readonly static Foo Instance = new Foo();
> }
>

>
> Существует ли какая-нибудь возможность логики связать между собой два этих поведения?

Измени механизм инициализации Instance (сделай static конструктор Foo и там проводи инициализацию). В том-же коде, что ты привел NullReferenceException это правильное поведение.
Posted via RSDN NNTP Server 1.9
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: Конструкторы в .NET
От: EM Великобритания  
Дата: 29.05.05 16:13
Оценка:
Здравствуйте, 0Z, Вы писали:


0Z>И еще, нельзя из нестатической функции использовать статические члены класса (вроде так в спецификации написано).


Так можно, наоборот нельзя
Опыт — это такая вещь, которая появляется сразу после того, как была нужна...
Re[2]: Конструкторы в .NET
От: Воронков Василий Россия  
Дата: 29.05.05 20:01
Оценка:
Здравствуйте, 0Z, Вы писали:

0Z>Здравствуйте, Воронков Василий, Вы писали:


0Z>В этой строчке кода:

ВВ>> public readonly static Foo Instance = new Foo();

0Z>вызывается конструктор:

ВВ>> private Foo()
ВВ>> {
ВВ>> Instance.Invoke();//NullReferenceException
ВВ>> }

0Z>А т.к. в этот момент времени Instance еще не проинициализирована, то получаем NullReferenceException.


Что значит Instance не проинициализирована? Это значит что класс не проиниализирован. Если в тот момент когда конструктор вызван но код его не выполнен класс не считается проинициализированным то какого хрена в первом примере в конструкторе происходит виртуальный вызов?

0Z>И еще, нельзя из нестатической функции использовать статические члены класса (вроде так в спецификации написано).


можно
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Re[2]: Конструкторы в .NET
От: Воронков Василий Россия  
Дата: 29.05.05 20:01
Оценка:
Здравствуйте, TK, Вы писали:

TK>Измени механизм инициализации Instance (сделай static конструктор Foo и там проводи инициализацию). В том-же коде, что ты привел NullReferenceException это правильное поведение.


Да я не жалуюсь на поведение. Согласен, оно правильное. Просто как-то так получается что в обоих случаях мы имеем два совершенно разных но в то же время правильных поведения, что мне как-то не совсем понятно.
Собственно вопрос в следующем: когда идеологически класс считается проиницализированным? Оба примера которые я привел дают соверенно разные "точки зрения" на этот вопрос.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Re[3]: Конструкторы в .NET
От: ie Россия http://ziez.blogspot.com/
Дата: 30.05.05 05:32
Оценка:
Здравствуйте, Воронков Василий, Вы писали:


0Z>>А т.к. в этот момент времени Instance еще не проинициализирована, то получаем NullReferenceException.


ВВ>Что значит Instance не проинициализирована? Это значит что класс не проиниализирован.


Нет, это значит лишь то, что значение Instance сменится с null на "правильное" только по окончанию вызова new Foo(). Помоему это вполне логично.

ВВ>Если в тот момент когда конструктор вызван но код его не выполнен класс не считается проинициализированным то какого хрена в первом примере в конструкторе происходит виртуальный вызов?


Должен происходить, тут проблема именно в инициализации переменной Instance.
Превратим окружающую нас среду в воскресенье.
Re[3]: Конструкторы в .NET
От: DuШes  
Дата: 30.05.05 05:39
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

[...]

что касается явной и неявной инициализации статических членов класса посмотри ссылку, которую уже раньше приводил:
Семь советов по применению статических полей, методов и классов
Конструкторы в .NET
От: Аноним  
Дата: 29.05.05 07:09
Оценка:
Если вы объясните, что означает "связать между собой два этих поведения", мой ответ будет более полезен.
Пока же я понял так, что вам хочется избавиться от NullReferenceException, сохранив интерфейс. Так?
Если это так, то в таком случае полезно разделить само создание объекта (т.е. конструктор) и инициализацию (т.е. вызов метода Invoke). Например, вот так:

public sealed class Foo
{    
    private Foo()    
    {    
    }        
    public void Invoke()    
    {        
    }
 
    private static Foo _instance = null;
    public static Foo Instance 
    {
        get
        {
            if ( _instance == null )            
            {
                _instance = new Foo(); // Создание
                _instance.Invoke(); // Инициализация
            }
            return _instance;
        }
    }
}

Обратите внимание, что это лишь общая суть решения. На практике придётся столкнуться с некоторыми доработками. Например, неплохо было бы обеспечить потокобезопасность свойства Foo.Instance.

Данная информация предоставляется на условиях «КАК ЕСТЬ», без предоставления каких-либо гарантий и прав. Используя данную информацию, вы соглашаетесь с тем, что (i) Майкрософт не несет ответственности за использование вами данной информации и (ii) вы принимаете на себя весь риск, связанный с использованием данной информации.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Конструкторы в .NET
От: Аноним  
Дата: 30.05.05 04:54
Оценка:
А скажите, пожалуйста, в чем вы видите противоречие? Первый пример абсолютно обычен. Перед вызовом конструктора класса-потомка автоматически вызывается конструктор класса-предка. То есть автоматический вызов происходит при наличии конструктора без параметров, а если бы конструктор Bar имел параметры, то компилятор даже попросил бы явно записать, как вызывать конструктор Bar. Нормальное поведение.

Второй пример меня очень порадовал. Очень хороший пример, спасибо. Кстати, какое поведение вы ожидали от него? Работает, в принципе, логично.

В самом начале программы (даже, возможно, до явного вызова конструктора Foo) происходит инициализация статического поля Instance. При этом в частности пытается запуститься нестатический метод Instance.Invoke(). Для запуска нестатического метода из статического должна быть указана ссылка на объект. Она и дана . Но вызов Instance.Invoke в первый раз происходит в самом конструкторе поля Foo.Instance. То есть во время выполнения оператора new. А оператор присваивания Instance = должен выполниться уж во всяком случае после выполнения new.

То есть во время первого запуска конструктора Foo поле Instance не определено. В этом можно убедиться, если установить Breakpoint в начале конструктора.

Если правда есть необходимость в таком решении, то можно использовать небольшой Workaround:

static int intField=0;
if(intField==0)
{
this.Invoke();
intField++;
return;
}


То есть при создании статического поля пользоваться ссылкой this.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Конструкторы в .NET
От: Воронков Василий Россия  
Дата: 30.05.05 18:18
Оценка:
Здравствуйте, Name, Вы писали:

N>Если вы объясните, что означает "связать между собой два этих поведения", мой ответ будет более полезен.

N>Пока же я понял так, что вам хочется избавиться от NullReferenceException, сохранив интерфейс. Так?
N>Если это так, то в таком случае полезно разделить само создание объекта (т.е. конструктор) и инициализацию (т.е. вызов метода Invoke). Например, вот так:

Мне не хочется ни от чего избавляться. Просто я привел два примера — причем оба довольно натянутые — когда, на мой взгляд, мы имеем весьма разное поведение. У каждого языка программирования есть как бы некоторая концепция. Так вот и расскажите мне такую концепцию согласно которой в конструкторе может производиться виртуальный вызов, когда экземпляр класса, что мы видим в примере 2, не считается проинициализированным.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Re: Конструкторы в .NET
От: Воронков Василий Россия  
Дата: 30.05.05 18:18
Оценка:
Здравствуйте, bukov_ka, Вы писали:

_>А скажите, пожалуйста, в чем вы видите противоречие? Первый пример абсолютно обычен. Перед вызовом конструктора класса-потомка автоматически вызывается конструктор класса-предка. То есть автоматический вызов происходит при наличии конструктора без параметров, а если бы конструктор Bar имел параметры, то компилятор даже попросил бы явно записать, как вызывать конструктор Bar. Нормальное поведение.


Ребята, вы меня не понимаете
Посмотри еще раз первый пост. Мне кажется я там довольно четко указал на то что происходит _виртуальный_ вызов метода Initialize до того, как выполнен код содержащийся в конструкторе класса, в котором этот метод определен. Это нормальное поведение? Да? Тогда см. пример 2.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Re[4]: Конструкторы в .NET
От: Воронков Василий Россия  
Дата: 30.05.05 18:18
Оценка:
Здравствуйте, DuШes, Вы писали:

DШ>что касается явной и неявной инициализации статических членов класса посмотри ссылку, которую уже раньше приводил:

DШ>Семь советов по применению статических полей, методов и классов

А по теме вопроса?
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Re: Конструкторы в .NET
От: Воронков Василий Россия  
Дата: 30.05.05 18:40
Оценка:
Здравствуйте, bukov_ka, Вы писали:

_>А скажите, пожалуйста, в чем вы видите противоречие? Первый пример абсолютно обычен. Перед вызовом конструктора класса-потомка автоматически вызывается конструктор класса-предка.


Кстати, это неправильно. Cначала вызывается именно конструктор Foo, затем вызывается конструктор Bar, выполняется код конструктора Bar, _виртуально_ вызывается Initialize (реализация которого есно содержится в Foo), затем выполняется код конструктора Foo. Таким образом метод Initialize виртуально выполняется до того как выполняется код в конструкторе Foo.

_>То есть автоматический вызов происходит при наличии конструктора без параметров, а если бы конструктор Bar имел параметры, то компилятор даже попросил бы явно записать, как вызывать конструктор Bar. Нормальное поведение.


Да, вот только здесь речь совершенно ни о об этом.

_>Второй пример меня очень порадовал. Очень хороший пример, спасибо. Кстати, какое поведение вы ожидали от него? Работает, в принципе, логично.


Всегда пожалуйста

_>В самом начале программы (даже, возможно, до явного вызова конструктора Foo) происходит инициализация статического поля Instance. При этом в частности пытается запуститься нестатический метод Instance.Invoke().


А что значит инициализация "статического поля Instance происходит до явного вызова конструктора Foo"? Конструктор закрытый — его явный вызов как раз и происходит во время инициализации. А теперь внимание, вопрос. Когда класс считается проинциализированным? После выполнения кода содержащегося в конструкторе? Но ведь конструкторе в дотнете красоты ради, когда конструктор вызывается все поля класса уже проинициализированны. Или же все-таки конструкторы не ради красоты.

_>Для запуска нестатического метода из статического должна быть указана ссылка на объект. Она и дана .


Ты о чем? Где это у меня статические методы?

_>Но вызов Instance.Invoke в первый раз происходит в самом конструкторе поля Foo.Instance. То есть во время выполнения оператора new. А оператор присваивания Instance = должен выполниться уж во всяком случае после выполнения new.


А после выполнения new это когда? Когда произошел _вызов_ конструктора или когда выполнился код содержащийся в конструкторе? Если второе — то см. первый пример.

В общем я устал писать. Вопрос простой. Зачем было сделано так что в конструкторе может происходить виртуальный вызов? Поначалу меня это удивляло, потом забавляло, а теперь просто кажется нелогичным. что лишний раз подтверждается тем что огромное кол-во неплохих дотнет-программистов с бекграундом в С++ вообще об этом не знают.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Re[2]: Конструкторы в .NET
От: ie Россия http://ziez.blogspot.com/
Дата: 31.05.05 04:06
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ> В общем я устал писать.


Устали писать — не пишите

ВВ> Вопрос простой. Зачем было сделано так что в конструкторе может происходить виртуальный вызов? Поначалу меня это удивляло, потом забавляло, а теперь просто кажется нелогичным.


Извините, что вопросом на вопрос. А собственно что тут нелогичного?
Сейчас глянун в свои проекты. В нескольких нашел такое поведение и, поверьте, ничего нелогичного. Другое дело, что надо избегать ситуаций типа:

public abstract class Bar
{
    protected Bar()
    {
        Initialize();
    }
    
    protected virtual void Initialize()
    {
    }
}


public class Foo : Bar
{
    private object obj;
    
    public Foo()
    {
    obj = new object();
    }
    
    protected override void Initialize()
    {
    obj.ToString();
    }
}


но это уже задача программиста. Плюс я заметил, что в комментах к таким конструкторам, как Bar, явно указывал, что вызывается виртуальный(абстрактный метод) такой-то. Так и Вам советую.
Превратим окружающую нас среду в воскресенье.
Re: Конструкторы в .NET
От: Аноним  
Дата: 31.05.05 04:45
Оценка:
>Кстати, это неправильно. Cначала вызывается именно конструктор Foo, затем вызывается конструктор Bar
На счет вызова конструктора Foo перед вызовом конструктора Bar — это вопрос мировоззрения Если в конструкторах и методах выводить сообщение, то получится такая цепочка вызовов в первом примере:
Bar
Foo.Initialize
Foo
То есть конструктор Bar вызывается до того, как выполнится первый оператор в конструкторе Foo. Поэтому я говорю о том, что конструктор Foo вызывается после.

>Конструктор закрытый — его явный вызов ...

Дико извиняюсь. Я делал его public и создавал экземпляр вместо того, чтобы вызывать Foo.Instance.Invoke(). Был не прав. Хотя исключение вылетает то же и по той же причине.

>конструкторы не ради красоты

Это уж точно. Объект класса инициализирован только после успешного завершения конструктора. Если конструктор кидает исключение, то объекта нет и не будет. По крайней мере так все работает в C++. Деталей реализации C# я, к сожалению не знаю, но внешне все выглядит также.

>А после выполнения new это когда?

Когда выполнен успешный выход из конструктора.

>нестатического метода из статического

Еще раз извиняюсь. Ерунду сказал. Просто вызывается метод указанного объекта.

>Вопрос простой.

Теперь вопрос ясен. http://www.gotdotnet.ru/Communities/Common/Images/Emoticons/Smile.gif В принципе программист о чем-то же думал, когда писал "virtual" и "override". Любая перегрузка может нарушить работу класса, но это никого не останавливает. Я сам использовал вызов виртуального метода из конструктора (правда потом рефакторинг убил это http://www.gotdotnet.ru/Communities/Common/Images/Emoticons/Smile.gif). У меня в конструкторе базового класса производилась запись в лог, а классы-потомки переопределяли методы, которые отвечали за выдачу осмысленного сообщения о том, какой именно объект, что именно делает. Хотя не спорю, это не самый лучший образец ООП http://www.gotdotnet.ru/Communities/Common/Images/Emoticons/Smile.gif



данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[3]: Конструкторы в .NET
От: Воронков Василий Россия  
Дата: 31.05.05 05:09
Оценка:
Здравствуйте, ie, Вы писали:

ie>Извините, что вопросом на вопрос. А собственно что тут нелогичного?

ie>Сейчас глянун в свои проекты. В нескольких нашел такое поведение и, поверьте, ничего нелогичного. Другое дело, что надо избегать ситуаций типа:

Не верю. С точки зрения _концепции_ языка которая даже у C# должна быть когда экземпляр класса считается проициниализированным?
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Re[2]: Конструкторы в .NET
От: Воронков Василий Россия  
Дата: 31.05.05 05:09
Оценка:
Здравствуйте, bukov_ka, Вы писали:

>>Кстати, это неправильно. Cначала вызывается именно конструктор Foo, затем вызывается конструктор Bar

_>На счет вызова конструктора Foo перед вызовом конструктора Bar — это вопрос мировоззрения

А ты колл-стек посмотри. И никакого мировоззрения.

>>конструкторы не ради красоты

_>Это уж точно. Объект класса инициализирован только после успешного завершения конструктора.

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

_>Если конструктор кидает исключение, то объекта нет и не будет. По крайней мере так все работает в C++.


В С++ в конструкторе виртуального вызова не будет. И это _логично_.

_>Хотя не спорю, это не самый лучший образец ООП


И тем не менее непонятно, зачем в принципе была добавлена такая возможность. Что она дает? Унифицированное поведение виртуальных методов? Но это называется в одном месте убрали ляп, а в другом добавили..
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Re[4]: Конструкторы в .NET
От: ie Россия http://ziez.blogspot.com/
Дата: 31.05.05 05:36
Оценка: +1
Здравствуйте, Воронков Василий, Вы писали:

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


ie>>Извините, что вопросом на вопрос. А собственно что тут нелогичного?

ie>>Сейчас глянун в свои проекты. В нескольких нашел такое поведение и, поверьте, ничего нелогичного. Другое дело, что надо избегать ситуаций типа:

ВВ>Не верю. С точки зрения _концепции_ языка которая даже у C# должна быть когда экземпляр класса считается проициниализированным?


Сразу по завершению вызова конструктора.
Превратим окружающую нас среду в воскресенье.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.