Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.90/21: Рейтинг темы: голосов - 21, средняя оценка - 4.90
7 / 7 / 4
Регистрация: 25.03.2013
Сообщений: 117
.NET 4.x

Потокобезопасно изменить коллекцию

08.01.2014, 17:26. Показов 4847. Ответов 62
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Коллекция прибиндина (binding) к listbox-у на вьюшке. Данные из коллекции (статус) обновляются из интернета, что может происходить долго и для того, чтобы интерфейс не завис - все делаю в асинхронном методе. Проблема в том, что во время обновления юзверь может удалить или добавить в коллекцию items.
Попробывал заблочить клавиши "добавить" и "удалить" пока обновляется список, но беда - долго обновляться может а у юзверей нету терпения, и возможность удалять и добавлять в коллекцию данные во время ее обновления надо.
То как потокобезопасно изменять коллекцию?

Добавлено через 2 часа 30 минут
Есть предложения?) ТК я в тупике)
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
08.01.2014, 17:26
Ответы с готовыми решениями:

Изменить коллекцию в forEach
Задача: сделать uppercase всех слов, длина которых больше 3 символов. Как это сделать с помощью стрима? Мой набросок(значение элементов в...

Потокобезопасно ли одновременно добавлять в конец list обьекты и удалять из середины?
Добрый день. Потокобезопасно ли одновременно добавлять в конец list обьекты и удалять из середины? Есть два потока. Один парсит лист и...

Дано число R и коллекцию размера N. Преобразовать коллекцию, заменив все ее положительные элементы на число R
Всем доброго времени суток. Вот такая задачка. Дано число R и коллекция размера N. Преобразовать коллекцию, заменив все ее...

62
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
10.01.2014, 12:07
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Grishaco Посмотреть сообщение
У меня такое ощущение, что мы либо не понимаем друг друга, либо говорим об одном и том же, только по разному
Возможно
Цитата Сообщение от Grishaco Посмотреть сообщение
я написал класс
Это не тот вопрос. Вопрос конкрентно про GUI. Пользователь запускает долгую операцию, курсор (или еще какой элемент GUI) переводится в часы. По окончании операции, курсор должен вернуться в обычное состоянии IsWait=false;. Но функция не доживает до этого момента, получая внутри исключение (не важно какое, логика может быть сколь угодно сложной). Сообщение об ошибке (основываясь на вашем первом примере с глобальным логгером) пользователь конечно получит. Но курсор то кто будет возвращить в прежний вид?
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
10.01.2014, 12:15
Цитата Сообщение от pycture Посмотреть сообщение
Но курсор то кто будет возвращить в прежний вид?
Не знаю как вам, а по мне форма не должна этим заниматься. Вызываемая функция, должна обеспечить корректный возврат. А вот что будет происходить в самой функции это уже ее дело.
0
burning1ife
 Аватар для kenny69
1466 / 1287 / 294
Регистрация: 21.09.2008
Сообщений: 3,438
Записей в блоге: 9
10.01.2014, 12:49
ViewModel:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 private async void Start()
        {
            IsWait = true;
//Вот это можно вынести в отдельную функцию
            try
            {
                var result = await Task<string>.Factory.StartNew(() =>
                {
                    Thread.Sleep(5000); // Имитация длительной обработки...
                    throw new Exception("Uhaha!!!");
                });
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
//////////
            IsWait = false;
        }
0
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
10.01.2014, 13:22
Цитата Сообщение от kenny69 Посмотреть сообщение
ViewModel
а try-catch тоже нельзя использовать
И как
Цитата Сообщение от Grishaco Посмотреть сообщение
Вызываемая функция, должна обеспечить корректный возврат.
без конструкций try (если не считать особо извращенных спсособов, удобство применения которых вызывает большой вопрос) для мест, которые могут непредсказуемым образом упасть, но GUI надо вернуть в нормальное состояние, я не представляю
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
10.01.2014, 13:29
Цитата Сообщение от pycture Посмотреть сообщение
а try-catch тоже нельзя использовать
Вы немного утрируете ситуацию, давайте представим, что форма это просто представление, которое работает с неким объектом через биндинги, какая обработка может быть в форме? Все ложится на некий объект, а вот как он там работает это уже никого не касается.
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
10.01.2014, 17:24
Разрулю: функции модели в случае ошибки обязаны бросать исключение. Что делать с этим исключением - решать будет GUI. Если у нас есть метод Hello, ( Потокобезопасно изменить коллекцию ), и он может свалиться, он не должен try catch'ить и возвращать какие-то флаги, а должен упасть с исключением, а гуй должен оборачивать это в try catch и уже реагировать так, как ему хочется. Если вызывается что-то в тысяче мест, try catch ли, еще что-то ли, то есть такая классная штука, как Extract Method.

C#
1
2
3
4
5
6
7
8
9
10
11
12
static Hello TryCreateHelloAndCatchInGui(string msg)
{
   try
   {
      return new Hello(msg);
   }
   catch (ArgumentNullException ex)
   {
      MessageBox.Show(ex.ToString());
      return null;
   }
}
и все дела.
После этого в коде вместо
C#
1
var hello = new Hello("Hi!");
будет
C#
1
var Hello = TryCreateHelloAndCatchInGui("Hi!");
имя я специально выбрал длинное, чтобы подразнить, и чтоб мне сказали, что стало намного длиннее. Но по факту получается корректная система: модель кинула исключение, контроллер (в нашем случае она же вьюшка) перехватила и обработала как ей хочется.

Добавлено через 1 минуту
Если уж совсем невмоготу, то можно объявить один глобальный хандлер для исключений, который будет обрабатывать все и без try catch.
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
10.01.2014, 17:27
Psilon, спасибо.

Цитата Сообщение от Psilon Посмотреть сообщение
функции модели в случае ошибки обязаны бросать исключение.
Не соглашусь, только по одной причине, работая с DevExpress и используя binding очень часто сталкиваюсь с тем, что любое исключение теряется в глубинах DevExpress.

Цитата Сообщение от Psilon Посмотреть сообщение
Что делать с этим исключением - решать будет GUI.
1. Если GUI обрабатывает исключение (использует try-catch), я считаю что программист написал корявый код. Все должно разруливаться валидацией и вместо ловли исключения сказать пользователю "Ах какой ты не хороший, нельзя оставлять пустое значение."
2. Опять же из вашего примера GUI не обрабатывает исключения, это делает менеджер, заглушка, называйте как хотите.

Я бы сделал так и не парился, как говорится и волки сыты и овцы целы

C#
1
2
3
4
5
6
7
8
9
10
11
12
static bool CreateHelloAndCatchInGui(string msg, out Hello hello, out string error)
{
error = string.Empty;
hello = null;
   if(!string.IsNullOrEmpty(msg))
{
hello = new Hello(msg);
      return  true;
}
error = "Ошибка!";
      return false;
}
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
10.01.2014, 17:38
Цитата Сообщение от Grishaco Посмотреть сообщение
Не соглашусь, только по одной причине, работая с DevExpress и используя binding очень часто сталкиваюсь с тем, что любое исключение теряется в глубинах DevExpress.
А в DevExpress идеальные программисты, которые никогда не ошибаются? Как раз-таки чем крупнее разработка, тем больше в ней глупых косяков. Самым чистым продуктом, который я видел из крупных, я на данный момент считаю Qt.
1. Если GUI обрабатывает исключение (использует try-catch), я считаю что программист написал корявый код. Все должно разруливаться валидацией и вместо ловли исключения сказать пользователю "Ах какой ты не хороший, нельзя оставлять пустое значение."
Модель не имеет права проводить никакой валидации. То есть может, но в случае невалидных данных она может только одно - бросить исключение. Подробнее ознакомится можно здесь

Добавлено через 4 минуты
Grishaco, и расскажите о use case'ах такого метода?
C#
1
2
3
4
5
6
7
8
9
string hello;
string exception;
if (!CreateHelloAndCatchInGui("Hi!", out hello, out exception)
{
   MessageBox.Show(exception);
   // processing further
   // ...
   return;
}
тут даже строк получается больше, чем в оригинале. В моем же случае
C#
1
2
3
var hello = CreateHelloAndCatchInGui("Hi!");
if (hello == null)
   return;
еще раз: исключения обрабатываться должны только в функции наивысшего уровня абстракции.

Добавлено через 3 минуты
Опять же из вашего примера GUI не обрабатывает исключения, это делает менеджер, заглушка, называйте как хотите.
А что в вашем случае является "Обработкой в GUI"? как отличить код в GUI от кода не в GUI? Если он лежит в том же файле - пожалуйста, в одном файле может быть много классов. Если он лежит в том же классе - так этот код и может быть статическим методом класса Form. Если он не должен использовать гуй - как же, использует, MessageBox - типичнейший пример. А оборачивать нормальные исключения в булевские флаги с кучей выходных параметров через out в стиле С лохматых годов - это, извините, не очень правильно.
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
10.01.2014, 18:03
Цитата Сообщение от Psilon Посмотреть сообщение
Grishaco, и расскажите о use case'ах такого метода?
Пример по сути абстрактный.

Вот пример use case

Кликните здесь для просмотра всего текста
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
public partial class Form1 : Form
    {
        private readonly Test _testDataSource;
 
        public Form1()
        {
            InitializeComponent();
            _testDataSource = new Test();
            testBindingSource.DataSource = _testDataSource;
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            ValidateData();
        }
 
        private bool ValidateData()
        {
            string error;
            if (!_testDataSource.Validate(out error))
            {
                MessageBox.Show(error);
                return false;
            }
            return true;
        }
 
        private void button2_Click(object sender, EventArgs e)
        {
            if (ValidateData())
            {
                helloBindingSource.DataSource = _testDataSource.GetHello();
            }
        }
 
        #region Windows Form Designer generated code
 
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.button1 = new System.Windows.Forms.Button();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.textBox2 = new System.Windows.Forms.TextBox();
            this.textBox3 = new System.Windows.Forms.TextBox();
            this.button2 = new System.Windows.Forms.Button();
            this.textBox4 = new System.Windows.Forms.TextBox();
            this.helloBindingSource = new System.Windows.Forms.BindingSource(this.components);
            this.testBindingSource = new System.Windows.Forms.BindingSource(this.components);
            ((System.ComponentModel.ISupportInitialize)(this.helloBindingSource)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.testBindingSource)).BeginInit();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(33, 86);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(75, 23);
            this.button1.TabIndex = 0;
            this.button1.Text = "Calc";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // textBox1
            // 
            this.textBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.testBindingSource, "X", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
            this.textBox1.Location = new System.Drawing.Point(8, 8);
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(100, 20);
            this.textBox1.TabIndex = 1;
            // 
            // textBox2
            // 
            this.textBox2.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.testBindingSource, "Y", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
            this.textBox2.Location = new System.Drawing.Point(8, 34);
            this.textBox2.Name = "textBox2";
            this.textBox2.Size = new System.Drawing.Size(100, 20);
            this.textBox2.TabIndex = 2;
            // 
            // textBox3
            // 
            this.textBox3.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.testBindingSource, "Result", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
            this.textBox3.Location = new System.Drawing.Point(8, 60);
            this.textBox3.Name = "textBox3";
            this.textBox3.Size = new System.Drawing.Size(100, 20);
            this.textBox3.TabIndex = 3;
            // 
            // button2
            // 
            this.button2.Location = new System.Drawing.Point(33, 115);
            this.button2.Name = "button2";
            this.button2.Size = new System.Drawing.Size(75, 23);
            this.button2.TabIndex = 0;
            this.button2.Text = "Hello";
            this.button2.UseVisualStyleBackColor = true;
            this.button2.Click += new System.EventHandler(this.button2_Click);
            // 
            // textBox4
            // 
            this.textBox4.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.helloBindingSource, "Result", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
            this.textBox4.Location = new System.Drawing.Point(8, 144);
            this.textBox4.Name = "textBox4";
            this.textBox4.Size = new System.Drawing.Size(100, 20);
            this.textBox4.TabIndex = 3;
            // 
            // helloBindingSource
            // 
            this.helloBindingSource.DataSource = typeof(WindowsFormsApplication3.Hello);
            // 
            // testBindingSource
            // 
            this.testBindingSource.DataSource = typeof(WindowsFormsApplication3.Test);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 261);
            this.Controls.Add(this.textBox4);
            this.Controls.Add(this.textBox3);
            this.Controls.Add(this.textBox2);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.button2);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "Form1";
            ((System.ComponentModel.ISupportInitialize)(this.helloBindingSource)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.testBindingSource)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();
 
        }
 
        #endregion
 
        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.TextBox textBox2;
        private System.Windows.Forms.TextBox textBox3;
        private System.Windows.Forms.BindingSource testBindingSource;
        private System.Windows.Forms.Button button2;
        private System.Windows.Forms.TextBox textBox4;
        private System.Windows.Forms.BindingSource helloBindingSource;
    }
 
    public class Test : INotifyPropertyChanged
    {
        private object _result;
        private object _x;
 
        private object _y;
 
        public object X
        {
            get { return _x; }
            set
            {
                if (_x != value)
                {
                    _x = value;
                    OnPropertyChanged("X");
                }
            }
        }
 
        public object Y
        {
            get { return _y; }
            set
            {
                if (_y != value)
                {
                    _y = value;
                    OnPropertyChanged("Y");
                }
            }
        }
 
        public object Result
        {
            get { return _result; }
            set
            {
                if (_result != value)
                {
                    _result = value;
                    OnPropertyChanged("Result");
                }
            }
        }
 
        public Hello GetHello()
        {
            return new Hello(Result.ToString());
        }
 
        public bool Validate(out string error)
        {
            error = string.Empty;
            int x;
            if (X == null || !int.TryParse(X.ToString(), out x))
            {
                error = "Некорректное значение X";
                return false;
            }
 
            int y;
            if (Y == null || !int.TryParse(Y.ToString(), out y))
            {
                error = "Некорректное значение Y";
                return false;
            }
            if (y == 0)
            {
                error = "Попытка деления на 0";
                return false;
            }
            Result = x/y;
            return true;
        }
 
        #region Implementation of INotifyPropertyChanged
 
        public event PropertyChangedEventHandler PropertyChanged;
 
        public void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
 
        #endregion
    }
 
    public class Hello
    {
        public Hello(string mess)
        {
            if (mess == null)
                throw new ArgumentNullException("mess");
 
            double res;
            double.TryParse(mess, out res);
            Result = res;
        }
 
        public double Result { get; private set; }
    }


Нет никаких try-catch
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
10.01.2014, 18:29
Grishaco, так можно и весь throw убрать, нафиг он тогда нужен, если данные всегда валидируются? Всегда считал защитное программирование усложняющей код фигней, без которой легко обойтись. У вас для каждого класса тогда нужен класс-прокладка, который будет валидировать все входные данные. И что получаем? А получаем удвоение количества кода, при этом никто не гарантирует, что Hello не будет вызван еще кем-то (вы же код пишете не один , ваш коллега вполне может не знать о ваших предпочтениях), вызовет Hello с null'ом и получит исключение. Почешит репу, да и добавит try catch. Тем более, что фактически вместо класса Hello у вас косячный класс Test. Еще раз: модель в случае некорректных данных должна бросать исключения, булевские функции Validate и Check должны носить исключительно характер private/protected или отсутствовать вовсе!


Пример: что если у нас есть метод MainMethod, в котором вызывается метод класса Test3, в котором вызывается метод класса Test2, в котором вызывается метод класса Test - Validate. Пусть у нас некорректные данные и произошла ошибка. MainMethod хочет в случае ошибки что-то сделать. Вопрос: как вы будете пробрасывать через всю эту архитектуру ошибку? В случае исключений ничего делать не надо - исключение само пробрасывается вверх по стеку, пока не найдет хандлер. Ну ладно, допустим, мы сделали return'ы и булевский флаг прокинули вверх. А тут прикол, кроме строки ошибки нужно вывести еще специальный GUID ошибки. Добавляем новое поле out для Test. Перестает работать Test2. Окей, туда тоже добавляем это поле. Перестает работать Test3. Е-мое, добавляем и туда. Теперь не работает MainMethod - не существует перегрузки метода Validate, которая принимает число аргументов (1). Блин, ну ладно, добавили еще одно поле. Чувствуете, какая веселая связность получается?

Добавлено через 2 минуты
P.S. Исключения в языке как раз призваны убрать все эти методы Check и Validate, сделать проверку ошибок более наглядной без тонн If (Check(a,b,c) && Validate(a,d,e)), и ими нужно пользоваться, а не "ой, я тут лучше утрою число кода и сделаю все с помощью логики, зато нету try catch, какой я молодец". У вас все выглядит типа неплохо, только потому, что у вас исключения нигде не обрабатываются. То есть оно может быть вызвано, но это нигде не обрабатывается. Такие дела.
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
10.01.2014, 18:41
Цитата Сообщение от Psilon Посмотреть сообщение
Почешит репу, да и добавит try catch
В том то и дело что не напишет. Иначе код просто обрастет try-catch. И кто дает гарантию, что NullReference придет из Hello, а если ниже, тогда как быть? Да вы поставили в модели try-catch и что? Пришло исключение, а где гарантия того, что оно пришло оттуда, откуда мы его ожидали?

Цитата Сообщение от Psilon Посмотреть сообщение
у вас косячный класс Test
В чем это он косячный. Класс как класс.

Цитата Сообщение от Psilon Посмотреть сообщение
вызовет Hello с null'ом и получит исключение
А вот что бы не получить исключение он заранее побеспокоится о невалидных данных, если это GUI скажет пользователю, если что-то другое тут уже по ситуации. Или вызов для получения исключения или дефолтное значение.

Цитата Сообщение от Psilon Посмотреть сообщение
Пример: что если у нас есть метод MainMethod, в котором вызывается метод класса Test3, в котором вызывается метод класса Test2, в котором вызывается метод класса Test - Validate.
Не совсем корректный пример, такой вложенности нет, вся валидация пишется в одном месте и для одного контрола, вы же понимаете, что переменные X,Y, так для примера, в данном случае приходят несколько объектов и валидируются они по разному в разных формах.

Цитата Сообщение от Psilon Посмотреть сообщение
В случае исключений ничего делать не надо - исключение само пробрасывается вверх по стеку, пока не найдет хандлер.
В моем примере выше именно так и есть, может я и параноик, но использование try-catch вместо валидации мне кажется не айс.

Прогер пишет, тестер тестирует находит все баги, которые были пойманы глобальным обработчиком, сливает прогеру, он в свою очередь исправляет всю валидацию. Все профит, какие бы данные не ввел пользователь он об этом узнает и они всегда валидны без try-catch в коде.

А вот если допустить такой вариант, что используются try-catch, тогда получается, что глатаются все исключения (или вы всегда в catch пишите конкретное исключение?).

Добавлено через 2 минуты

Не по теме:

Цитата Сообщение от Psilon Посмотреть сообщение
ой, я тут лучше утрою число кода и сделаю все с помощью логики, зато нету try catch, какой я молодец
Можно вопрос, сколько человек у вас в команде и как часто они меняются?

0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
10.01.2014, 19:27
Grishaco, я не спорю, что есть практика, когда есть валидирующий слой, который проверяет все входные данные, и если они корректные, передает их далее в систему, но я считаю это неправильным, потому что
Не совсем корректный пример, такой вложенности нет, вся валидация пишется в одном месте и для одного контрола, вы же понимаете, что переменные X,Y, так для примера, в данном случае приходят несколько объектов и валидируются они по разному в разных формах.
либо по классу на каждый класс, который валидируем, либо получаем god object, который нашпигован логикой проверки всего, от валидности строк до стейта высокоуровневых объектов.

Не по теме:

Можно вопрос, сколько человек у вас в команде и как часто они меняются?
ну человек 20, за последний год ушел один человек, пришло 4



Добавлено через 2 минуты
Grishaco, еще раз: такой подход практикуется, с прослойкой, но во-первых проповедовать его как едиинственный православный не надо, а во-вторых если он используется, то из внутреннего кода, который типа всегда работает с валидными данными убираются вообще все проверки. В принципе в этом и заключается смысл этого подхода, иначе получаем усложнение безо всякого профита.

http://habrahabr.ru/post/191548/
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
10.01.2014, 19:32
Цитата Сообщение от Psilon Посмотреть сообщение
но я считаю это неправильным
Ну тут как обычно на вкус и цвет. У вас свои практики у меня свои.

Можно увидеть ваш вариант решения задачи с классом Hello и X, Y, Result?

Цитата Сообщение от Psilon Посмотреть сообщение
иначе получаем усложнение безо всякого профита.
Т.е. по вашему такой код более верный и менее сложный и упрощает код?

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
try
            {
                x =int.Parse("");
            }
            catch (FormatException)
            {
                MessageBox.Show("");
            }
            try
            {
                x = int.Parse("");
            }
            catch (FormatException)
            {
                MessageBox.Show("");
            }
            try
            {
                r = x/y
            }
            catch (DivideByZeroException)
            {
                MessageBox.Show("");
            }
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
10.01.2014, 19:35
Ну если вы для каждой строчки пишете try catch и она раздувается в 6 раз - я не удивлен, что вы его недолюбливаете..
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
10.01.2014, 19:37
Цитата Сообщение от Psilon Посмотреть сообщение
Ну если вы для каждой строчки пишете try catch и она раздувается в 6 раз - я не удивлен, что вы его недолюбливаете..
Вообще это пример, давайте сделаем по другому

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
try
            {
                x =int.Parse("");
                y = int.Parse("");
                r = x/y
            }
            catch (FormatException)
            {
                MessageBox.Show("");
            }
            catch (DivideByZeroException)
            {
                MessageBox.Show("");
            }
Только как в узнаете, что некорректное Х или Y?
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
10.01.2014, 19:47
Ну в таком случае напишу свой аналог TryParse (если его нету стандарте). И в самом try parse все равно будет try {parse(); return true;} catch {return false;}, без него никуда.
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
10.01.2014, 19:52
Цитата Сообщение от Psilon Посмотреть сообщение
И в самом try parse все равно будет try {parse(); return true;}
Так тут вы приходите к моему коду.

Или это все таки будет такой вариант

C#
1
2
3
4
5
6
7
public int TryParse(string s)
        {
            int r;
            if (int.TryParse(s, out r))
                return r;
            throw new Exception("Некорректное значение X");
        }
1
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
10.01.2014, 20:59
Grishaco, что значит я прихожу к вашему варианту? Либо мы юзаем исключения, и имеем try catch, либо мы юзаем валидацию, тогда у нас в методе Hello не должно быть throw. А код выше это обычный Parse. TryParse на то и Try, что он глотает исключение. Но как он устроен?
C#
1
2
3
4
5
6
7
8
9
try
{
   parse();
   return true;
}
catch
{
  return false;
}
за что боролись, на то и напоролись. Все равно чтобы написать метод tryparse нужно использовать try catch. А я всего лишь говорю, что эти методы должны содержать не в модели, а в вызывающем коде, если не в самой форме, то в каком-нибудь менеджере, но все равно пользовательском. У меня ХШ нет, я не знаю, что там пользователь хочет делать с моей функцией. Принцип бусидо: валидные данные - все хорошо, невалидные - бросаем исключение. В принципе ваш пример не опровергает, а как раз подтверждает мою точку зрения (не этот бредовый код, прямо над этим постом, а выше). Существует менеджер (в вашем случае Test), это пользовательский класс, который валидирует данные для модели. И тут есть два случая: первый - вы пишете библиотеку для себя и знаете, что вы будете валидировать все данные - защищенная зона => выкидываются все проверки и надеемся на то, что нам не подсунут вместо входных данных каку. Второй - пишете библиотеку, которой будут пользовать непонятно как, и могут во входные параметры засунуть что угодно - тогда мы пишем всевозможные throw в начале всех публичных методов. У вас первый вариант - отлично, но и второй существует...
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
10.01.2014, 21:17
Цитата Сообщение от Psilon Посмотреть сообщение
Grishaco, что значит я прихожу к вашему варианту?
Я приводил вот такой код выше

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private static IWCFCallback callback;
 
        public static bool IsConnect()
        {
            try
            {
                callback.Ping();
                return true;
            }
            catch
            {
                return false;
            }
        }
Цитата Сообщение от Psilon Посмотреть сообщение
тогда у нас в методе Hello не должно быть throw
Это почему, здесь я как раз подстраховался на случай, если другой программист начнет юзать этот класс. Я обработал входные данные и использую его без try-catch или это плохо.

Цитата Сообщение от Psilon Посмотреть сообщение
Все равно чтобы написать метод tryparse нужно использовать try catch
Зачем try catch, если есть методы нормального получения данных, int.TryParse наконец.

Цитата Сообщение от Psilon Посмотреть сообщение
И тут есть два случая
Я описываю класс со всеми проверками, в случае чего кидаю исключение. Создаю на него Unit test. Потом при работе, просто валидирую все входные данные, как раз для того что бы не использовать try-catch.

Я не могу понять смысла кидать исключение и потом его ловить. Зачем объясните? Если заранее я знаю что null нельзя и будет исключение.
1
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
10.01.2014, 21:46
Цитата Сообщение от Grishaco Посмотреть сообщение
Зачем try catch, если есть методы нормального получения данных, int.TryParse наконец.
забавно, я думал он устроен иначе. Но обычно все же tryDoSomething() обычно заключаются в том, что этот DoSomething() вызывается в try, а в catch пишется return false.

Цитата Сообщение от Grishaco Посмотреть сообщение
Я описываю класс со всеми проверками, в случае чего кидаю исключение. Создаю на него Unit test. Потом при работе, просто валидирую все входные данные, как раз для того что бы не использовать try-catch.
давайте на этом и закончим, а то уже в демагогию перерастает. Без try catch можно писать, но тогда вы а) уверены, что функция не упадет с валидными данными (например, мы пытаемся достучаться по валидному url, мы его проверили регкспами, все прекрасно, но интернета нет и сайт недоступен), б) вы уверены, что правильно проверили все входные параметры (чтобы узнать, какие параметры валидны, вы должны узнать, как устроен метод и что именно он хочет - является ли null-строка валидной, или она должна быть string.Empty, или она должна быть непустой, или она должна начинаться с буквы или цифры,...), что полностью нарушает принцип инкапсуляции. Имхо надеяться, что эти условия выполнены, немного самонадеянно, а если это так (хотя это гарантировать нереально), то это обозначает сильнейшую завязанность компонент друг на друга.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
10.01.2014, 21:46
Помогаю со студенческими работами здесь

Отобразить коллекцию
Возник следующий вопрос: Некоторым образом формируется коллекция документов. Хотелось бы всю эту коллекцию выводить во вью в...

Реализовать коллекцию
Задание. Создать класс Student с двумя полями и конструктором с параметрами. Если нужно добавить в класс дополнительные методы или...

Отсортировать коллекцию
Нужно отсортировать объем двигателя (FUELCONSUMPTION ) по возрастающей public class Bentley extends AbstractCar { private...

Заполнить коллекцию
Создать коллекцию для пар Student, int. Создать метод который будет добавлять в коллекцию пару Student, int. Целое число должно быть...

Объект в коллекцию
Хочу, чтобы объекты которые я создаю (Person person1 = new Person), каждый при создании, автоматически ложился в List и я мог вывести на...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
20. Мат мед. Абсентеизм как отдельный тип простоя
anaschu 29.05.2026
Апдейт модели: исправленные баги, абсентеизм и новые механизмы Продолжаю развивать ранее описанную модель рабочего коллектива на AnyLogic. За последние несколько дней был проведён серьёзный. . .
19. здоровье, усталость и психотип работника влияют на производительность предприятия, и наоборот, производительность на здоровье, усталось и психотип
anaschu 28.05.2026
Дискретно-событийная модель рабочего коллектива на AnyLogic: здоровье, выгорание, психотипы и микростимуляция Привет, коллеги. Хочу поделиться итогами нескольких недель работы над симуляционной. . .
"Прокси" для последовательного порта
Eddy_Em 28.05.2026
Эту штуку написал я достаточно давно. Но сейчас вот понадобилось настроить датчик грозы, но при этом не отключать его от "метеодемона". Соответственно, надо запустить этот "прокси": метеодемон будет. . .
Рефакторинг программы уравнивания.
Massaraksh7 26.05.2026
Пример по предыдущей записи в блоге. Но, надо заметить, что, во-первых, там оптимизация не только математики, но и работы с базой данных, и с графами, а во-вторых, это ещё не всё.
Использование TThread в Lazarus для математических вычислений.
Massaraksh7 25.05.2026
Производя рефакторинг своих программ на предмет ускорения их работы, обратил внимание на такой аспект, как сокращение времени матвычислений. Дело в том, что приходится работать с большими матрицами. . .
Модель здравосохранения 18. Чем здоровее работник, тем быстрее выгорает
anaschu 24.05.2026
Имитационная модель корпоративного здравоохранения: что показывает математика Сегодня в модели рабочего коллектива на AnyLogic появились три новые механики — выгорание через накопленную усталость,. . .
Модель здравосохранения 17. Планы на выгорание
anaschu 23.05.2026
Вот конкретная схема реализации: В классе Работник добавить: накопленнаяУсталость — растёт каждый час работы, снижается в перерывы и болезни коэффициентПрезентеизма — снижает продуктивность. . .
Изменение цветов в палитре gif файла aka фавикона
russiannick 23.05.2026
Изменение цветов в палитре gif файла, юзаемого как фавиконка в составе html-файла, помещенная в base64, средствами нативного Java Script, навеянное сном в майский день. Для работы необходим браузер,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru