powered by simpleCommunicator - 2.0.55     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / SmtpClient, проблема, вскипает мозк, помогите плиз
64 сообщений из 64, показаны все 3 страниц
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38131711
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
День добрый, плиз хелп по проблеме!

Есть класс для отправки почты

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
    public class MailSender : IDisposable
    {
        SmtpClient SC;
        MailMessage Mess;
        public MailSender(string subj, string body, string F_Att)
        {
            SC = new SmtpClient("192.168.55.55", 25);
            SC.Credentials = new NetworkCredential("username", "password");
            Mess = new MailMessage("mail@mail.ru", "mail@mail.ru");
            Mess.Body = body;
            Mess.Subject = subj;
            Mess.Attachments.Add(new Attachment(F_Att));
        }
        public void Send()
        {
            SC.Send(Mess);
        }
        public void Dispose()
        {            
            GC.SuppressFinalize(this);
        }
    }



В контексте другого класса происходит перебор в foreach элементов DataRow,
который содержит (ну пусть хотя бы ID темы письма - это не суть) и имя файла для отправки.
Вызывается метод Send()

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
        private void Upl_USZN_NewInst()
        {
            DataTable DT = (DataTable)DM.Get_UplUsznFileList(100000, Convert.ToInt32(Program.SPID));
            string Dir = @"c:\DIR\";
            //DT.Rows:
            //100000 | file1.dbf
            //100001 | file2.dbf
            //100000 | file3.dbf
            //100001 | file4.dbf
            foreach (DataRow R in DT.Rows)
            {                
                    File.WriteAllBytes(Dir + R["FileUpload"].ToString(), Properties.Resources.empty);
                    //подготовка файла для отправки по почте
                    DM.SP_Upload_Uszn(100000, Convert.ToInt32(Program.SPID), Dir, R["FileUpload"].ToString());
                    if (R["SubDivisionID"].ToString() == "100000")
                    {
                        using (MailSender MS = new MailSender("subj0", "", Dir + R["FileUpload"].ToString()))
                        {
                            MS.Send();
                        }
                    }
                    if (R["SubDivisionID"].ToString() == "100001")
                    {
                        using (MailSender MS = new MailSender("subj1", "", Dir + R["FileUpload"].ToString()))
                        {
                            MS.Send();
                        }
                    }
            }
            F_Refresh();
            MessageBox.Show("Файлы выгружены");
            return;
        }



Весь глюк в том, что отправляются ВСЕ письма, кроме последнего письма, соответствующего последней строчке в DataRows.
Причем и это письмо всетаки отправится, если после вызова Upl_USZN_NewInst() сразу закрыть программу.
Если подождать с закрытием программы минуть 5, то письмо не отправится.
В чем проблема?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38131729
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exec88,

нехорошо реализован класс MailSender

в Dispose нужно сделать SC.Dispose()
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38131740
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Изопропилexec88,

нехорошо реализован класс MailSender

в Dispose нужно сделать SC.Dispose()

В .Net 3.5 у него нет метода Dispose().
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38131857
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
exec88,
Спасибо! Помогло. Перестроил под четверку, там есть Dispose();
А что еще некрасиво реализовано в классе?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38131858
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропилнехорошо реализован класс MailSender

+1.
я наследую свой класс от этого шаблона
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
    public abstract class DisposableTemplate: IDisposable
    {
        #region Implementation of IDisposable (with finalizer)

        ~DisposableTemplate()
        {
            Dispose(false);
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        private void Dispose(bool disposing)
        {
            if (!IsDisposed)
            {
                if (disposing)
                    DisposeManagedResources();

                DisposeUnmanagedResources();

                IsDisposed = true;
            }
        }

        #endregion

        #region For overrides

        
        protected abstract void DisposeManagedResources();
        protected abstract void DisposeUnmanagedResources(); 

        #endregion

        #region Property

        public bool IsDisposed { get; private set; }

        #endregion
    }



А вообще для приведенной реализации MailSender вообще Dispose не нужно
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
    public class MailSender
    {
        private readonly SmtpClient _sc;
        
        public MailSender(string address, int port, string login, string password)
        {
            _sc = new SmtpClient(address, port);

            if (false == string.IsNullOrEmpty(login))
                _sc.Credentials = new NetworkCredential(login, password);
        }

        public void Send(string from, string to, string subj, string body, string attachement)
        {
            using (var mess = new MailMessage(from, to))
            {
                mess.Body = body;
                mess.Subject = subj;
                mess.Attachments.Add(new Attachment(attachement));

                _sc.Send(mess);
            }
        }
    }
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38131887
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79, спасибо
А вообще для приведенной реализации MailSender вообще Dispose не нужно
Я его сделал только, чтобы использовать MailSender в конструкции using
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38131909
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exec88,

В методе Dispose нужно сделать
Код: c#
1.
2.
SC.Dispose() и
Mess.Dispose()



(если уж сказали, что убираем за собой - так убираем до конца)
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38131914
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exec88Я его сделал только, чтобы использовать MailSender в конструкции using

Зачем? Если вы используете 3.5 (как изначально написали), то MailSender в конструкции using абсолютно бесполезен.

Если > 3.5, то

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
    public class MailSender: DisposableTemplate
    {
        private readonly SmtpClient _sc;
        
        public MailSender(string address, int port, string login, string password)
        {
            _sc = new SmtpClient(address, port);

            if (false == string.IsNullOrEmpty(login))
                _sc.Credentials = new NetworkCredential(login, password);
        }

        public void Send(string from, string to, string subj, string body, string attachement)
        {
            using (var mess = new MailMessage(from, to))
            {
                mess.Body = body;
                mess.Subject = subj;
                mess.Attachments.Add(new Attachment(attachement));

                _sc.Send(mess);
            }
        }

        #region Overrides of DisposableTemplate

        protected override void DisposeManagedResources()
        {
            _sc.Dispose();
        }

        protected override void DisposeUnmanagedResources()
        {
            // неуправляемых ресурсов нет, метод пуст
        }

        #endregion
    }
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38131921
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
offtopic:

метод "private void Upl_USZN_NewInst()" демонстрирует все "прелести" работы с DataTable :-)
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38131936
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Прикол живёт в потрохах старого фреймворка. TCP соединения c SMTP сервером после отправки почты не закрываются а помещаются в служебный пул.

Если приложение топикстартера закрывается быстро - соединение закрывает клиент,пул очищается штатным путём, сервер получает команду QUIT, всё в порядке

SMTP сервер обычно не любит долго ждать и закрывает соединение на своём конце.
При этом в случае топикстартера не получивши команды QUIT он зачем-то дропает последнее письмо.

Главное - никакой мистики(просто сложилось несколько багофич)

2 exec88: При отправке одиночного письма при авторЕсли подождать с закрытием программы минуть 5, то письмо не отправится.с фреймворком 3.5 - письмо отправляется?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38131958
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
так много раз делать не надо:
R["FileUpload"].ToString()
R["SubDivisionID"].ToString()
один раз присвоили переменной и используете.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132014
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Изопропилexec88,

В методе Dispose нужно сделать
Код: c#
1.
2.
SC.Dispose() и
Mess.Dispose()



(если уж сказали, что убираем за собой - так убираем до конца)
Я это и сделал, только раньше проект был под 3.5, в этой версии метода Dispose Не было.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132018
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ИзопропилПрикол живёт в потрохах старого фреймворка. TCP соединения c SMTP сервером после отправки почты не закрываются а помещаются в служебный пул.

Если приложение топикстартера закрывается быстро - соединение закрывает клиент,пул очищается штатным путём, сервер получает команду QUIT, всё в порядке

SMTP сервер обычно не любит долго ждать и закрывает соединение на своём конце.
При этом в случае топикстартера не получивши команды QUIT он зачем-то дропает последнее письмо.

Главное - никакой мистики(просто сложилось несколько багофич)

2 exec88: При отправке одиночного письма при авторЕсли подождать с закрытием программы минуть 5, то письмо не отправится.с фреймворком 3.5 - письмо отправляется?
одиночного - да
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132025
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79так много раз делать не надо:
R["FileUpload"].ToString()
R["SubDivisionID"].ToString()
один раз присвоили переменной и используете.
Согласен, а что там еще не так?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132046
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exec88,

На диск точно нужно файлы записывать?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132057
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exec88Согласен, а что там еще не так?

Там всё не так, но более точно можно будет сказать, когда увижу код DM.Get_UplUsznFileList, DM.SP_Upload_Uszn

сходу анализ на "100000" слишком громоздкий. может так проще, если всего два значения?
Код: c#
1.
2.
3.
4.
using (MailSender MS = new MailSender(R["SubDivisionID"].ToString() == "100000" ? "subj0" : "subj1", "", Dir + R["FileUpload"].ToString()))
{
    MS.Send();
}
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132089
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Изопропилexec88,

На диск точно нужно файлы записывать?
Как вариант. На диске создается пустышка - dbf.
Потом SQL ная хэпэшка записывает в нее данные.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132096
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exec88Как вариант. На диске создается пустышка - dbf.
Потом SQL ная хэпэшка записывает в нее данные.
ХП - на диск сама пишет? Жестоко.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132108
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79exec88Согласен, а что там еще не так?

Там всё не так, но более точно можно будет сказать, когда увижу код DM.Get_UplUsznFileList, DM.SP_Upload_Uszn

сходу анализ на "100000" слишком громоздкий. может так проще, если всего два значения?
Код: c#
1.
2.
3.
4.
using (MailSender MS = new MailSender(R["SubDivisionID"].ToString() == "100000" ? "subj0" : "subj1", "", Dir + R["FileUpload"].ToString()))
{
    MS.Send();
}



DM.Get_UplUsznFileList, DM.SP_Upload_Uszn
это методы, которые возвращают результат выполнения ХП.
По поводу анадиза на 100000 - вопрос вообще не принципиальный, т.к. там чуть позже будут не ID,
а конкретные e-mail адреса и все сразу будет подставляться
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132115
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Изопропилexec88Как вариант. На диске создается пустышка - dbf.
Потом SQL ная хэпэшка записывает в нее данные.
ХП - на диск сама пишет? Жестоко.
А что - нормуль :-)
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132131
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exec88а конкретные e-mail адреса и все сразу будет подставляться
Может, когда будет нормальная реализация, тогда и поговорим?

exec88А что - нормуль :-)
Не, не нормуль. Совсем.

Берите прямо с базы данные, кидайте в стрим, и делайте сразу аттачмент

Конструктор Attachment(Stream, ContentType) инициализирует новый экземпляр класса Attachment с указанным потоком и типом содержимого.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132182
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79exec88а конкретные e-mail адреса и все сразу будет подставляться
Может, когда будет нормальная реализация, тогда и поговорим?

exec88А что - нормуль :-)
Не, не нормуль. Совсем.

Берите прямо с базы данные, кидайте в стрим, и делайте сразу аттачмент

Конструктор Attachment(Stream, ContentType) инициализирует новый экземпляр класса Attachment с указанным потоком и типом содержимого.
А как определить ContentType для dbf файла определенной структуры и кодировки dos 866 ?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132275
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exec88А как определить ContentType для dbf файла определенной структуры и кодировки dos 866 ?
Content-type: application/octet-stream (от структуры не зависит, просто двоичные данные)
кодировка задаётся собственно в самом dbf
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132344
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Изопропилexec88А как определить ContentType для dbf файла определенной структуры и кодировки dos 866 ?
Content-type: application/octet-stream (от структуры не зависит, просто двоичные данные)
кодировка задаётся собственно в самом dbf
так самого то dbf еще нет! А когда он уже будет с данными, то смысла со стримом уже нет, его можно приэттачить по имени файла. Или я неправильно понял?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132364
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exec88так самого то dbf еще нет! А когда он уже будет с данными, то смысла со стримом уже нет, его можно приэттачить по имени файла. Или я неправильно понял?

Вас вообще трудно понять :-)

Вы сказали, что дбф формируется хранимкой. Соттветственно, все данные, необходимые для генерации, в этой хранимке доступны. Так почему же вместо ненормальной записи в файл просто не выдать эти данные клиенту в рекодсете?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132394
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79exec88так самого то dbf еще нет! А когда он уже будет с данными, то смысла со стримом уже нет, его можно приэттачить по имени файла. Или я неправильно понял?

Вас вообще трудно понять :-)

Вы сказали, что дбф формируется хранимкой. Соттветственно, все данные, необходимые для генерации, в этой хранимке доступны. Так почему же вместо ненормальной записи в файл просто не выдать эти данные клиенту в рекодсете?
Я тоже не совсем Вас понимаю.
1) Мой вариант. До отправки письма есть пустой dbf - нужной структуры и кодировки. Есть хранимка, которая сама заполняет этот dbf файл. Сгенерить снуля dbf хранимка не может, только вставить данные в имеющийся (в t-sql я не нашел как создать dbf из под хранимки без использования clr). Когда заполненный dbf файл уже на диске есть, он эттачится к письму через FilePath.
2) Вы предлагаете. Есть данные полученные хранимкой, Вы имеете в виду DataTable или что - то в этом духе, их кидаем с стрим. Как я понял, Вы имеете в виду, что есть еще dbf файл (откуда он, это пустышка?). И можно в эттаче склеить dbf файл со стримом? Может код черкнете, понятнее станет...
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132415
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79Изопропилнехорошо реализован класс MailSender

+1.
я наследую свой класс от этого шаблона
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
    public abstract class DisposableTemplate: IDisposable
    {
        #region Implementation of IDisposable (with finalizer)

        ~DisposableTemplate()
        {
            Dispose(false);
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        private void Dispose(bool disposing)
        {
            if (!IsDisposed)
            {
                if (disposing)
                    DisposeManagedResources();

                DisposeUnmanagedResources();

                IsDisposed = true;
            }
        }

        #endregion

        #region For overrides

        
        protected abstract void DisposeManagedResources();
        protected abstract void DisposeUnmanagedResources(); 

        #endregion

        #region Property

        public bool IsDisposed { get; private set; }

        #endregion
    }



А вообще для приведенной реализации MailSender вообще Dispose не нужно
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
    public class MailSender
    {
        private readonly SmtpClient _sc;
        
        public MailSender(string address, int port, string login, string password)
        {
            _sc = new SmtpClient(address, port);

            if (false == string.IsNullOrEmpty(login))
                _sc.Credentials = new NetworkCredential(login, password);
        }

        public void Send(string from, string to, string subj, string body, string attachement)
        {
            using (var mess = new MailMessage(from, to))
            {
                mess.Body = body;
                mess.Subject = subj;
                mess.Attachments.Add(new Attachment(attachement));

                _sc.Send(mess);
            }
        }
    }




А почему var mess = new MailMessage(from, to))
Чтобы не утруждаться писать MailMessage?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132439
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exec881) Мой вариант. До отправки письма есть пустой dbf - нужной структуры и кодировки. Есть хранимка, которая сама заполняет этот dbf файл. Сгенерить снуля dbf хранимка не может, только вставить данные в имеющийся (в t-sql я не нашел как создать dbf из под хранимки без использования clr). Когда заполненный dbf файл уже на диске есть, он эттачится к письму через FilePath.
2) Вы предлагаете. Есть данные полученные хранимкой, Вы имеете в виду DataTable или что - то в этом духе, их кидаем с стрим. Как я понял, Вы имеете в виду, что есть еще dbf файл (откуда он, это пустышка?). И можно в эттаче склеить dbf файл со стримом? Может код черкнете, понятнее станет...

Я имею ввиду, что заниматься генерацией файла (или его заполнением) из ХП - неверно архитектурно. Если очень хочется, можно SSIS использовать

Но я бы получил на клиента рекордсет, и из клиента закидывал бы в файл. А если посильнее напрячься, можно и на лету генерировать, но нужно разобраться со структурой dbf
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132441
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exec88Чтобы не утруждаться писать MailMessage?
да
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132499
exec88
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79exec881) Мой вариант. До отправки письма есть пустой dbf - нужной структуры и кодировки. Есть хранимка, которая сама заполняет этот dbf файл. Сгенерить снуля dbf хранимка не может, только вставить данные в имеющийся (в t-sql я не нашел как создать dbf из под хранимки без использования clr). Когда заполненный dbf файл уже на диске есть, он эттачится к письму через FilePath.
2) Вы предлагаете. Есть данные полученные хранимкой, Вы имеете в виду DataTable или что - то в этом духе, их кидаем с стрим. Как я понял, Вы имеете в виду, что есть еще dbf файл (откуда он, это пустышка?). И можно в эттаче склеить dbf файл со стримом? Может код черкнете, понятнее станет...

Я имею ввиду, что заниматься генерацией файла (или его заполнением) из ХП - неверно архитектурно. Если очень хочется, можно SSIS использовать

Но я бы получил на клиента рекордсет, и из клиента закидывал бы в файл. А если посильнее напрячься, можно и на лету генерировать, но нужно разобраться со структурой dbf
Да, я думал, но C# не очень изящно работает с dbf. Видать для него это уже старая технология.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38132527
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Arm79А если посильнее напрячься, можно и на лету генерировать, но нужно разобраться со структурой dbf

exec88Да, я думал, но C# не очень изящно работает с dbf. Видать для него это уже старая технология.
да какая разница в какой формат сериализовать. DBF прост как 3 копейки
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38684482
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1001209&msg=13855091
http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1001209&msg=13855388

Тоже показался интересным такой вариант реализации шаблона Dispose . Хотя бы потому, что в ещё одной реализации этого шаблона, взятой из МСДН все наследники базового класса, в котором этот шаблон реализован, должны скопировать кучу кода из этого базового класса. См., например, раздел "Implementing the dispose pattern for a derived class" - по сути, от базового класса остаётся только Dispose() без параметров. А в реализации автора по двум первым ссылкам бОльшая часть базового класса - переиспользуемая (надо только переопределить два метода), да плюс освобождение ресурсов явно сгруппировано по управляемым и неуправляемым.

Но вот с реализациями в наследниках этого базового класса у меня возникли вопросы. Если в примере в МСДН более-менее расписано, то тут - нет.

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

Я разобрал такой случай: класс наследуется от класса, унаследованного от DisposableBase, и имеет члены, унаследованные от DisposableBase.

Вот моя реализация (с муляжами неуправляемых ресурсов в виде переменных int), где описанный класс - Е:


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
public class E : D
{
	public B EB { get; set; }
	public int FileHandleE { get; set; }

	protected override void DisposeManagedResources()
	{
		Console.WriteLine("E_DisposeManagedResources");
		EB.Dispose();
		base.DisposeManagedResources();
	}

	protected override void DisposeUnmanagedResources()
	{
		Console.WriteLine("E_DisposeUnmanagedResources");
		FileHandleE = default(int);
		base.DisposeUnmanagedResources();
	}
}




Вот весь код с промежуточными классами (А, B и т. п.) и с проверочной программой:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
public class A : DisposableBase
{
	public int FileHandleA { get; set; }

	protected override void DisposeManagedResources()
	{
		Console.WriteLine("A_DisposeManagedResources");
	}

	protected override void DisposeUnmanagedResources()
	{
		Console.WriteLine("A_DisposeUnmanagedResources");
		FileHandleA = default(int);
	}
}

public class B : A
{
	public int FileHandleB { get; set; }

	protected override void DisposeManagedResources()
	{
		Console.WriteLine("B_DisposeManagedResources");
		base.DisposeManagedResources();
	}

	protected override void DisposeUnmanagedResources()
	{
		Console.WriteLine("B_DisposeUnmanagedResources");
		FileHandleB = default(int);
		base.DisposeUnmanagedResources();
	}
}

public class C : B
{
	public int FileHandleC { get; set; }

	protected override void DisposeManagedResources()
	{
		Console.WriteLine("C_DisposeManagedResources");
		base.DisposeManagedResources();
	}

	protected override void DisposeUnmanagedResources()
	{
		Console.WriteLine("C_DisposeUnmanagedResources");
		FileHandleC = default(int);
		base.DisposeUnmanagedResources();
	}
}

public class D : DisposableBase
{
	public A DA { get; set; }
	public int FileHandleD { get; set; }

	protected override void DisposeManagedResources()
	{
		Console.WriteLine("D_DisposeManagedResources");
		DA.Dispose();
	}

	protected override void DisposeUnmanagedResources()
	{
		Console.WriteLine("D_DisposeUnmanagedResources");
		FileHandleD = default(int);
	}
}

public class E : D
{
	public B EB { get; set; }
	public int FileHandleE { get; set; }

	protected override void DisposeManagedResources()
	{
		Console.WriteLine("E_DisposeManagedResources");
		EB.Dispose();
		base.DisposeManagedResources();
	}

	protected override void DisposeUnmanagedResources()
	{
		Console.WriteLine("E_DisposeUnmanagedResources");
		FileHandleE = default(int);
		base.DisposeUnmanagedResources();
	}
}

class Program
{
	static void Main(string[] args)
	{
		A a = new A();
		a.Dispose();
		Console.WriteLine();

		B b = new B();
		b.Dispose();
		Console.WriteLine();

		C c = new C();
		c.Dispose();
		Console.WriteLine();

                // Можно проверить FileHandle - всё нормально "освобождается".
		D d = new D();
		d.DA = new A();
		Console.WriteLine(d.FileHandleD.ToString() + d.DA.FileHandleA.ToString() + " " + d.DA.IsDisposed + " " + d.IsDisposed);
		d.FileHandleD = 5;
		d.DA.FileHandleA = 2;
		Console.WriteLine(d.FileHandleD.ToString() + d.DA.FileHandleA.ToString() + " " + d.DA.IsDisposed + " " + d.IsDisposed);
		d.Dispose();
		Console.WriteLine(d.FileHandleD.ToString() + d.DA.FileHandleA.ToString() + " " + d.DA.IsDisposed + " " + d.IsDisposed);

		Console.WriteLine();

		E e = new E();
		e.EB = new B();
		e.DA = new A();
		e.Dispose();

		Console.Read();
	}
}




А вот вывод, относящийся к освобождению ресурсов класса Е:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
E_DisposeManagedResources
B_DisposeManagedResources
A_DisposeManagedResources
B_DisposeUnmanagedResources
A_DisposeUnmanagedResources
D_DisposeManagedResources
A_DisposeManagedResources
A_DisposeUnmanagedResources
E_DisposeUnmanagedResources
D_DisposeUnmanagedResources



По-моему, всё правильно.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38684484
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Мой DisposableBase - это копия DisposableTemplate у Arm79.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38684490
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А вообще, мне вся эта возня с Dispose напоминает ту же возню с деструкторами в С++. Тоже помню, что в учебниках по С++ писали такие портянки со сложными наследованиями, а потом в деструкторах писали сообщения, чтобы понять, что и когда вызывается. Вот и тут один в один.

В связи с этим у меня в голове сидит вопрос - а нафига?! Нафига всё это автоматическое управление памятью, чтобы облегчить работу программистам, когда на самом деле всё чуть ли не сложнее стало, чем было в С++? За что боролись, на то и напоролись?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38684510
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
HomeCoder,

Dispose - не для освобождения памяти. а для освобождения неуправляемых ресурсов.


авторЗа что боролись, на то и напоролись?
не нравится - пишите на с++
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38684540
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ИзопропилHomeCoder,

Dispose - не для освобождения памяти. а для освобождения неуправляемых ресурсов.
Я, может, неправаильно где-то выразился... Или мы говорим об одном и том же разными словами... Я просто хотел, чтобы посмотрели на мой пример работы с Dispose Pattern в случае сложной иерархии классов. Я вот проверку набросал в консольном приложении - вроде, всё работает.

ИзопропилавторЗа что боролись, на то и напоролись?
не нравится - пишите на с++
Да я не веду речь о "нравится/не нравится". Я просто столкнулся с такой мыслью и хочу узнать у коллег - есть ли у них такое же ощущение.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38684559
Фотография D129
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
HomeCoderесть ли у них такое же ощущение.
Нет.
В плюсах - деструктор надо было писать и вызывать всегда, для всех классов.
В шарпе - диспоз только тогда, когда без него никак.
Из всех классов, которые я написал, пожалуй только парочка была с реализацией этого интерфейса....

Разница весьма ощутимая. 100% и 0.001%.
:-)
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38684598
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А вопрос то в чем?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38684736
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
HomeCoder,
авторА вообще, мне вся эта возня с Dispose напоминает ту же возню с деструкторами в С++.
говорите правильно Dispose это просто паттрен, по рекомендации мс и как правило, для освобождения нр,
но мс сам то не всегда придерживается кое где этого, что нам мешает в местячковом коде применить его и для не освобождения ресурсов?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685097
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79А вопрос то в чем?
Я хотел узнать, правильно ли я использую этот паттерн в случае со сложным наследованием-композицией классов. В МСДН разобран только самый простой пример. У вас разобран только самый простой пример. - Когда мы просто наследуемся от базового класса, который реализует IDisposable.

Я же разбираю пример, когда мы наследуемся от класса, реализующего базовый абстрактный класс, реализующий IDisposable (и шаблон Dispose), да плюс ещё имеем в композиции объекты классов, унаследованных от класса, реализующего тот же базовый абстрактный класс, реализующий IDisposable. Надеюсь, понятно объяснил. В коде это выглядит так, как я показал - http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1001209&msg=16242281

Теперь я словами поясню, что я делаю в классе Е. Основное я выделю жирным шрифтом. Извиняюсь, что длинно, но нигде ведь не написано, как надо делать.

Начинается всё с того, что я вызываю метод Dispose в объекте класса Е - см. код в конце Program.Main. Поскольку метод Dispose объявлен и реализован только в самом базовом абстрактном классе DisposableBase, который реализует шаблон Dispose (и интерфейс IDisposable), то вызывается именно этот метод.

В методе Dispose сначала вызывается абстрактный метод DisposeManagedResources. Поскольку этот метод переопределён в каждом унаследованном классе, то в объекте типа Е будет вызван вариант с перегрузкой в классе Е. В методе DisposeManagedResources я должен освободить управляемые ресурсы. Поскольку у класса Е управляемые ресурсы находятся как в иерархии наследования, так и в композиции, то я должен освободить и то, и другое. В композиции я освобождаю управляемые ресурсы, вызвав EB.Dispose(), а в наследовании - вызвав базовую реализацию DisposeManagedResources.

Затем в методе Dispose вызывается абстрактный метод DisposeUnmanagedResources. Опять же, вызывается самая последняя по наследованию реализация, т. к. этот метод тоже переопределён во всех унаследованных классах. Неуправляемые ресурсы освобождаются путём собственно освобождения неуправляемых ресурсов (у меня этот "зануление" импровизированного указателя на файл), плюс вызовом базовой реализации метода DisposeUnmanagedResources.


Основные концепции такого комплексного освобождения:

1. Шаблон в данной реализации (когда код освобождения ресурсов находится в специальных методах DisposeManagedResources и DisposeUnmanagedResources) предполагает, что в каждом последующей иерархии наследования эти методы будут переоределяться. При этом в каждом переопределении должна быть вызвана базовая реализация этих методов.

2. Освобождение управляемых ресурсов в иерархии наследования происходит в методе DisposeManagedResources через вызов базовой реализации метода DisposeManagedResources. Освобождение управляемых ресурсов в композиции происходит в методе DisposeManagedResources через вызовы методов Dispose для всех ресурсов в композиции.

3. Освобождение неуправляемых ресурсов в иерархии наследования происходит в методе DisposeUnmanagedResources через вызов базовой реализации метода DisposeUnmanagedResources. Освобождение неуправляемых ресурсов в композиции происходит в методе DisposeUnmanagedResources через собственно специальный код освобождения для каждого неуправляемого ресурса в композиции.


Я проверил всю эту простынку в коде, привёл код здесь - любой может запустить и проверить. Вроде, всё по простынке делается.

Я только хочу узнать, правильно ли я применяю данный шаблон в таком сложном случае? Правильна ли последовательность освобождения ресурсов?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685099
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вы, конечно, можете говорить, что Dispose редко где применяете, и такие огромные конструкции не нужны. Однако, если посмотреть вглубь любого класса .NET, то он так или иначе в своих базовых классах реализует IDisposable. Потому что это для нас .NET абстрагирует всё в управлении памятью, а на самом деле он работает со вполне реальными объктами в памяти, поэтому у классов .NET полно реализаций освобождения.


Из вышеприведённой простыни я могу сделать такой вывод: если в нашем классе где-то в иерархии наследования или в композиции реализуется IDisposable (т. е. используется класс, работающий с неуправляемыми ресурсами), то и нашему классу желательно реализовывать шаблон Dispose - чтобы структурировать логику освобождения ресурсов, а не где попало вызывать Dispose базового класса или объекта из композиции. Правильно?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685102
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Я там, в своём коде , привёл вывод последовательности вызовов освобождений для такой сложной иерархии. Очень похоже на то, как плюсовики трясутся над правильным порядком вызова деструкторов в своих сложных иерархиях классов. Только у них две заботы: освобождение памяти и вызов базовых деструкторов. А у нас - четыре: освобождение управляемой памяти и вызов базовых освободителей управляемой памяти, освобождение неуправляемой памяти и вызов базовых освободителей неуправляемой памяти. Поэтому я и говорю, что дотнетчикам гораздо больше головной боли, чем плюсовикам, если начать тесно работать с неуправляемыми ресурсами.

Кто-нибудь вообще над подобным задумывался?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685103
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
авторосвобождение управляемой памяти
Вместо "памяти" там везде "ресурсы" лучше поставить.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685121
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
HomeCoder,
Вы как то мудрено завернули пример, можно же проще ( экономьте наше время, и желание разбираться)
это?
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
class Program
    {
        static void Main(string[] args)
        {
            using (var b=new B())
            {
                 
            }
            Console.Read();
        }
    }

    class BaseD:IDisposable
    {
        protected virtual void OnDispose()
        {
            Console.WriteLine(1);
        }
        public void Dispose()
        {
            OnDispose();
        }
    }

    class A:BaseD
    {
        protected override void OnDispose()
        {
            Console.WriteLine(2);
            base.OnDispose();
        }
    }

    class B:A
    {
        protected override void OnDispose()
        {
            Console.WriteLine(3);
            base.OnDispose();
        }
    }



если да, так в принципе эта фишка к диспозе не относится, обыкновенные заглушки, для переопределения в последующих классах
применяются сплошь и рядом даже своя специфика в названиях, порядок освобождения нр абсолютно не играет роли.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685175
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Где-то в степи,

ну, типа того. Только у вас в наследовании всего лишь, а у меня ещё и в композиции.

Ну да, переопределять в наследнике и вызывать потом ещё и реализацию через base - это к более общим практикам относится, чем только к Dispose.

Вобщем, я пока подвохов в своём подходе не вижу. Разве что высвобождать неуправляемые ресурсы ещё рекомендуют через try/finally в блоке finally - ну чтобы точно освободились.

А ещё какая-то практика есть, чтобы после Dispose или просто, когда объект уже не нужен, назначать объектам null - это что, быстрее и вернее заставит сборщика мусора на самом деле освободить ресурсы, или это маразм и перестраховка сиплюсплюсников?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685179
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Понимаете, если вот это всё вместе собрать:

- Dispose,
- Dispose(bool),
- ~Finalize,
- не забыть присвоить null,
- разделяем высвобождение управляемых и неуправляемых ресурсов,
- неуправляемые - в finally (через try/finally)

то получается, что плюсовики просто детскими забавами занимаются. Им всего-то надо вызвать деструкторы и занулить указатели.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685180
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
using и прочий SafeHandle - это когда у вас где-то локально неуправляемое (но под управляемой обёрткой) что-то создаётся, типа файла или там соединения с БД, и вы тут же это, после использования, высвобождаете. А когда у вас неуправляемый ресурс или пусть даже управляемая обёртка над неуправляемым ресурсом - часть композиции или наследования, то тут как раз вся эта ворожба с Dispose и всплывает.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685182
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
HomeCoder,
Да никаких практик нет, сборщик мусора то и вообще не знает ни про какие диспозе.
вся магия заключается в переопределении метода финализатора type Object
при определении объекта с переопределенным методом, это объект помещается в таблицу объектов с у которых есть финализатор.
вот и все, при недостижении и срабатывании уборщика вызывается метод финализатора ( а там исполняется код освобождения нр)
если конечно программист заранее этот код не вызвал, так сказать защита от дурака срабатывает..
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685190
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
HomeCoderЯ же разбираю пример, когда мы наследуемся от класса, реализующего базовый абстрактный класс, реализующий IDisposable (и шаблон Dispose), да плюс ещё имеем в композиции объекты классов, унаследованных от класса, реализующего тот же базовый абстрактный класс, реализующий IDisposable. Надеюсь, понятно объяснил. В коде это выглядит так, как я показал - http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1001209&msg=16242281
В общем случае наследник от класса, в свою очередь наследующего от абстрактного класса DisposableBase, по поведению ничем не отличается от классов, наследующих от других классов. Так что вы правильно применяли override


HomeCoder1. Шаблон в данной реализации (когда код освобождения ресурсов находится в специальных методах DisposeManagedResources и DisposeUnmanagedResources) предполагает, что в каждом последующей иерархии наследования эти методы будут переоределяться. При этом в каждом переопределении должна быть вызвана базовая реализация этих методов.
Нет, не верно. Они МОГУТ переопределяться, но не обязательно должны. Например, в наследнике никаких иных объектов с IDisposable можно не объявлять, поэтому и переопределять DisposeManagedResources нет смысла (за исключением наследования от абстрактного класса). А вызывать или нет базовую реализацию в переопределенном методе - на совести программиста. Ведь метод может быть и абстрактным, и банально пустым. Или работа идет с protected членами.



HomeCoderЯ только хочу узнать, правильно ли я применяю данный шаблон в таком сложном случае? Правильна ли последовательность освобождения ресурсов?
Да


HomeCoderИз вышеприведённой простыни я могу сделать такой вывод: если в нашем классе где-то в иерархии наследования или в композиции реализуется IDisposable (т. е. используется класс, работающий с неуправляемыми ресурсами), то и нашему классу желательно реализовывать шаблон Dispose - чтобы структурировать логику освобождения ресурсов, а не где попало вызывать Dispose базового класса или объекта из композиции. Правильно?
Нет. Например, в полях может быть объявлен SqlConnection con.
А в методе можно вызывать:
using (con = new SqlConnection()) {
чего то там
}


HomeCoderА у нас - четыре: освобождение управляемой памяти и вызов базовых освободителей управляемой памяти, освобождение неуправляемой памяти и вызов базовых освободителей неуправляемой памяти. Поэтому я и говорю, что дотнетчикам гораздо больше головной боли, чем плюсовикам, если начать тесно работать с неуправляемыми ресурсами.

Кто-нибудь вообще над подобным задумывался?
Конечно. Я может вам тайну открою, но работа с неуправляемыми ресурсами (не имеющими обертки в Net) не настолько частая операция. Мне пришлось работать за несколько лет только один раз - когда подключал сишную либу для криптоопераций. В общем, так DisposeUnmanagedResources и появился в шаблоне.



Что касается шаблона, то несколько ремарок:
1) Использование финализатора на самом деле замедляет процесс "обнуления" объекта, так как он помещается в специальную очередь отдельно от остальных объектов
2) Финализатор в этом шаблоне нужен только для неуправляемых ресурсов. Если их нет, его можно упростить и выкинуть и финализатор, и DisposeUnmanagedResources
3) В шаблоне метод DisposeUnmanagedResources правильнее делать не абстрактным, а виртуальным. Тогда не обязательно каждый раз его переопределять в наследнике.



HomeCoderА ещё какая-то практика есть, чтобы после Dispose или просто, когда объект уже не нужен, назначать объектам null - это что, быстрее и вернее заставит сборщика мусора на самом деле освободить ресурсы, или это маразм и перестраховка сиплюсплюсников?
сборщик мусора он на то и сборщик, что работает сам. Стратегия работы сборщика может задаваться например в конфиге. Разумеется, можно вызвать и вручную GC.Collect, но это признак плохого тона.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685196
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Arm79 Разумеется, можно вызвать и вручную GC.Collect, но это признак плохого тона.
Если это делается в трезвом уме и ясном сознании - никакого плохого тона.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685313
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Большое спасибо за помощь.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38685318
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Завёл два базовых класса - DisposableWithUnmanagedBase и DisposableWithoutUnmanagedBase. Во втором классе убрал метод DisposeUnmanagedResources, убрал финализатор и упростил DisposeManagedResources.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38689105
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79HomeCoderА ещё какая-то практика есть, чтобы после Dispose или просто, когда объект уже не нужен, назначать объектам null - это что, быстрее и вернее заставит сборщика мусора на самом деле освободить ресурсы, или это маразм и перестраховка сиплюсплюсников?
сборщик мусора он на то и сборщик, что работает сам. Стратегия работы сборщика может задаваться например в конфиге. Разумеется, можно вызвать и вручную GC.Collect, но это признак плохого тона.
Если реальный вызов сборщика неопределён, то тогда есть смысл в присваивании null, как я думаю. Ибо часто встречаются конструкции вида

Код: c#
1.
2.
3.
4.
if (obj != null)
{
    obj.Dispose();
}



Вот после вызова Dispose есть смысл поставить obj = null.

Потому что сразу после вызова Dispose сборщик может и не вызваться, зато может быть:

1) снова будет вызван код выше;
2) кто-то другой попытается вызвать объект obj.

И если в 1) спасает правильный шаблон Dispose, который должен быть спроектироват так, чтобы было безопасно вызывать Dispose много раз подряд, то в 2) что спасёт? Может же быть такая ситуация, что сборщик ещё только начал удалять obj (т. е. obj ещё не null), а кто-то пытается его использовать?

Я правильно рассуждаю?


Или объясните уже наконец, ПОЧЕМУ многие присваивают null объектам?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38689108
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
HomeCoderИли объясните уже наконец, ПОЧЕМУ многие присваивают null объектам?
А особенно объектам, которые реализуют Dispose.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38689124
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
HomeCoderИ если в 1) спасает правильный шаблон Dispose, который должен быть спроектироват так, чтобы было безопасно вызывать Dispose много раз подряд, то в 2) что спасёт? Может же быть такая ситуация, что сборщик ещё только начал удалять obj (т. е. obj ещё не null), а кто-то пытается его использовать?

Я правильно рассуждаю?

Или объясните уже наконец, ПОЧЕМУ многие присваивают null объектам?

1) Null присваивают по разным причинам, и эти причины не всегда связаны с Dispose. Я вот отнюдь не всегда пишу null. Например,

var obj = new КакаяТоДиспозейблХрень();
try {
чего нить
} finally {
obj.Dispose()
}

Никакого присвоения null нет, obj далее не используется, когда его приберет сборщик мусора - мне неизвестно и совершенно неинтересно.

2) Если у вас несколько разных объектов пытаются вызывать Dispose у одного объекта, это неправильная архитектура (ИМХО). Всегда должно быть точно определено, кто создает объекты, и кто их уничтожает.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38691341
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ну а если такая ситуация, что объекты используются часто, и где-то вызвался Dispose. Если сборщик сразу не освобождает память, то может быть попытка использования объекта, для которого уже вызван Dispose. К чему это может привести? Вот эта неопределённость мне и не нравится. В С++ ты сделал delete объекта по указателю, присвоил указателю null и всё это произошло сразу - нет никаких недомолвок, что де сборщик какой-то не сразу всё удалил или удалил лишь частично.

Меня просто нервирует это. Сначала декларируется, что не надо думать об освобождении памяти. Потом вводится понятие Dispose (и это без всяких unsafe - с unsafe всё ещё усложняется). А потом говорится, что даже после всех этих Dispose и ручного вызова GC.Collect не обязательно сразу ресурсы будут освобождены. Сборщик мусора ещё подумает. Вводится понятие поколений объектов в мусорной куче (хорошее название для "кучи", хе-хе). Потом говорится, что и правилу поколений сборщик не всегда следует - есть де случаи, когда и объекты, которые уже должны быть удалены, всё ещё живут. И вот при такой неопределённости предлагается писать приложения.

При такой неопределённости простое присвоение null выглядит простым и эффективным способом избавиться от этих костылей. У нас же уже есть шаблон if (obj != null). Для таких общепринятых проверок простое присвоение null может быть хорошей практикой и гарантией, что не будет использования объекта, для которого уже был вызван Dispose, но который ещё фактически не освободился. Или освободился не полностью.


Я думаю, тут загвоздка вот в чём. Нужно разделять управление памятью (предотващение утечек и пр.) и логику использования объектов в коде.

GC занимается управлением памятью - т. е. предотвращает утечки и снимает с программиста работу по ручному освобождению ресурсов. Но он не защищает от использования объектов, которые по логике уже освобождены, а по факту - нет. От этого защищает присвоение null.

Когда говорят, что присваивать null не нужно, имеют ввиду, что это не нужно делать для освобождения ресурсов . Но не для защиты от использования объектов, которые по логике (только по логике, но ещё не на самом деле) уже освобождены. Сборщик мусора может сработать сильно позже и "занулить", объект, а использование объекта может быть раньше этого "зануления". Поэтому, чтобы такого неправильного использования не произошло, надо присваивать null объекту, который больше не предпоплагается использовать. Это не освобождает ресурсы, а всего лишь сигнализирует программисту о том, что этот объект СЧИТАЕТСЯ ОСВОБОЖДЁННЫМ.


Как вы считаете?


Просто уже нервирует, когда видишь проект, в котором в порядке вещей куча подобных вот

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
public void Shutdown()
{
    if (RasterState != null)
    {
        RasterState.Dispose();
        RasterState = null;
    }

    if (DepthStencilView != null)
    {
        DepthStencilView.Dispose();
        DepthStencilView = null;
    }

    if (DepthStencilState != null)
    {
        DepthStencilState.Dispose();
        DepthStencilState = null;
    }

    if (DepthStencilBuffer != null)
    {
        DepthStencilBuffer.Dispose();
        DepthStencilBuffer = null;
    }

    if (RenderTargetView != null)
    {
        RenderTargetView.Dispose();
        RenderTargetView = null;
    }

    if (Device != null)
    {
        Device.Dispose();
        Device = null;
    }

    if (SwapChain != null)
    {
        SwapChain.Dispose();
        SwapChain = null;
    }
}

...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38691485
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
HomeCoderЕсли сборщик сразу не освобождает память, то может быть попытка использования объекта, для которого уже вызван Dispose
1) В том шаблоне, который я приводил, есть свойство IsDisposed. Поэтому смело можно вызывать хоть 10 Dispose подряд. Исполнится только первый. Проверка на null нужна только чтобы убедиться, что объект существует. К ресурсам, которые этот объект использует, null никак не относится.

2) Вы не понимаете концепции управляемой памяти. Dispose нужен для скорейшего освобождения ресурсов. Например, соединения с БД, или файла. Но не для удаления объекта. Сами объекты можно не удалять вообще - это работа GC. Я бы даже сказал, что это предпочтительный стиль кодирования - куча мелких (и желательно immutable) объектов. В этом случае GC работает очень эффективно. И отказываться от такого стиля нужно только в случае особых обстоятельств, например, проседания по производительности

3) Код пишите вы, вот и обеспечивайте ситуацию, когда таких попыток не будет. У меня же получается. Не вижу причин, чтобы это не получалось у вас. Почему у вас по коду должно быть разбросано много мест, где делают Dispose? Делайте в одном месте.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38691600
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79,

я имел ввиду, что Dispose вызван, а объект продолжает кто-то вызывать. Не Dispose на объекте, а сам объект использовать - его методы, свойства и прочее. Т. е. ресурсы, которые использует этот объект, освобождены, а объект пытаются использовать с этими ресурсами. - Ошибка.

А если "занулить" объект, то и использовать нечего. - Хорошо.

А?

Может, стоить где-то в этот шаблон Dispose добавить зануление этого объекта? Типа this = null? Или что-то в этом роде.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38691606
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А, уже есть аналог - вместо null и проверки

if(obj != null)

надо использовать IsDisposed и проверку

if(obj.IsDisposed)

Правильно?

Только вот загвоздка - все знают шаблон проверки if(obj != null), а вот шбалон проверки if(obj.IsDisposed) не распространён. Надо запоминать, договариваться с коллегами, вводить правила, что для унаследованных от такого-то класса надо такие-то проверки делать. Потом в коде проверять, унаследован ли или нет... С null как-то более привычно и распространённо.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38691645
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
если HomeCoderDispose вызван, а объект продолжает кто-то вызывать, то это косяк архитектуры. И null здесь никак не поможет.
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38691676
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Arm79если HomeCoderDispose вызван, а объект продолжает кто-то вызывать, то это косяк архитектуры. И null здесь никак не поможет.
как и при обращении по висячей ссылке после удаления объекта в c++
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38691710
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
HomeCoder,
Dispose никакого отношения к уборке мусора не имеет, ну разве что запрет на вызов финализатора в классическом исполнении
Все ваши сепаратистские высказывания в стиле обращение к отдиспозеному объекту сводятся к простому -
обращение к объекту состояние которого программист изменил по незнанке и где реальный результат отличается от ожидаемого.
типа cm.CommandText=""; ну что тут ответить......... наверно имя - насрано...
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38692371
HomeCoder
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Тогда как вы можете прокомментировать постоынне заналливания после Dispose в примере кода , что я привёл?

Там автор писал, что он недостаточно опытен в С#. Более того, код был портирован с С++, где автор кода был более опытен. Можно это посчитать за старую привычку сиплюсплюсника?
...
Рейтинг: 0 / 0
SmtpClient, проблема, вскипает мозк, помогите плиз
    #38692394
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
HomeCoder,

от очистки ссылок польза есть - если по каким либо причинам объект, метод shutdown которого демострируется в примере, не удалится мусоросборщиком (ссылку кто либо удержит) - хвосты освободятся
...
Рейтинг: 0 / 0
64 сообщений из 64, показаны все 3 страниц
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / SmtpClient, проблема, вскипает мозк, помогите плиз
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]