Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.93/15: Рейтинг темы: голосов - 15, средняя оценка - 4.93
Модератор
8612 / 5941 / 1691
Регистрация: 21.04.2018
Сообщений: 17,670
Записей в блоге: 2
1

Проверка условия в конструкторе класса

08.09.2018, 18:16. Просмотров 3121. Ответов 16
Метки нет (Все метки)

В конструкторе класса при определённых условиях надо выйти без создания нового объекта. Подскажите на простом примере
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    public class MyClass
    {
 
        /// <summary>Возращает номер</summary>
        public int Number { get; }
 
        /// <summary>Скрытый конструктор без параметров</summary>
        public MyClass() { }
 
        /// <summary>Конструктор с новым номером</summary>
        /// <param name="NewNumber">Новый номер</param>
        public MyClass(int NewNumber)
        {
            if (Number < 0)
            {
                // Здесь надо выйти без создания объекта
            }
            Number = NewNumber;
        }
    }
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
08.09.2018, 18:16
Ответы с готовыми решениями:

Инициализация шаблонного класса(В конструкторе класса после двоеточия вновь имя класса)
Всем доброго времени суток! Пытаюсь разобраться как работает приведенный мной код. Конкретно,...

Ошибка при работе с объектом класса в конструкторе другого класса
Имеется данный код: https://github.com/ubelian/glgame/tree/master/glgame В файле Food.cpp в...

С++, delete в деструкторе класса не видит переменные, создаваемые new в конструкторе класса
#include &quot;stdafx.h&quot; #include &quot;iostream&quot; #include &quot;math.h&quot; using namespace std; class fun {...

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

16
1108 / 779 / 219
Регистрация: 15.08.2010
Сообщений: 2,159
08.09.2018, 18:25 2
Цитата Сообщение от Элд Хасп Посмотреть сообщение
/// <summary>Скрытый конструктор без параметров</summary>
* * * * public MyClass() { }
не скрытый
Цитата Сообщение от Элд Хасп Посмотреть сообщение
// Здесь надо выйти без создания объекта
выбросить исключение
Цитата Сообщение от Элд Хасп Посмотреть сообщение
public MyClass(int NewNumber)
заменить на uint и вообще не надо будет проверять
1
Неадекват
1430 / 1184 / 229
Регистрация: 02.04.2010
Сообщений: 2,718
Записей в блоге: 2
08.09.2018, 18:25 3
C#
1
throw new ArgumentException("NewNumber не может быть меньше нуля");
1
Эксперт .NET
4335 / 1997 / 387
Регистрация: 27.03.2010
Сообщений: 5,450
Записей в блоге: 1
08.09.2018, 19:02 4
Класс MyClass изменён, обрати внимание. Весь код - это просто пример для наглядности, какой-то скрытый смысл искать не стоит

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
using System;
 
namespace ConsoleApp1
{
    class Program
    {
        #region Entry point
 
        private static Program _program;
 
        static void Main(string[] args)
        {
            _program = new Program();
            _program.Run(args);
        }
 
        #endregion
 
        private void Run(string[] args)
        {
            MyClass myClass;
            int value = -12;
            while (!TryToCreateMyClass(value += 5, out myClass)) { }
 
            Console.WriteLine($"Number = {myClass.Number}");
            Console.ReadKey();
        }
 
        private bool TryToCreateMyClass(int value, out MyClass myClass)
        {
            try
            {
                myClass = new MyClass(value);
                return true;
            }
            catch (Exception ex)
            {
                LogError(nameof(TryToCreateMyClass), ex);
                myClass = null;
                return false;
            }
        }
 
        private void LogError(string message, Exception ex)
        {
            Console.WriteLine($"{message}. {ex.Message}");
        }
    }
 
    public class MyClass
    {
        /// <summary> Возвращает номер </summary>
        public int Number { get; }
 
        /// <summary> Скрытый конструктор без параметров </summary>
        private MyClass() { }
 
        /// <summary> Конструктор с новым номером </summary>
        /// <param name="newNumber"> Новый номер </param>
        public MyClass(int newNumber)
        {
            if (newNumber < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(newNumber));
            }
 
            Number = newNumber;
        }
    }
}
1
Модератор
8612 / 5941 / 1691
Регистрация: 21.04.2018
Сообщений: 17,670
Записей в блоге: 2
08.09.2018, 20:00  [ТС] 5
Цитата Сообщение от КОП Посмотреть сообщение
не скрытый
Случайная ошибка

Добавлено через 14 минут
Цитата Сообщение от КОП Посмотреть сообщение
выбросить исключение
Да, такой вариант я рассматривал. Но мне удобнее по функциям, если бы в таком случае объект не создавался - был равен null.

Что-то типа такого, как в примере ниже в статическом методе Create
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
        static void Main(string[] args)
        {
            MyClass ObjectOne = MyClass.Create(-1);
 
            MyClass ObjectTwo = new MyClass(-1);
 
        }
 
        public class MyClass
        {
 
            /// <summary>Возращает номер</summary>
            public int Number { get; private set; }
 
            /// <summary>Скрытый конструктор без параметров</summary>
            private MyClass() { }
 
            /// <summary>Конструктор с новым номером</summary>
            /// <param name="NewNumber">Новый номер</param>
            public MyClass(int NewNumber)
            {
                if (NewNumber < 0)
                {
                    // Здесь надо выйти без создания объекта
                }
                Number = NewNumber;
            }
 
            /// <summary>Статический метод создания нового объекта с новым номером</summary>
            /// <param name="NewNumber">Новый номер</param>
            public static MyClass Create(int NewNumber)
            {
                if (NewNumber < 0) return null;
                else return new MyClass() { Number = NewNumber };
            }
        }
Добавлено через 2 минуты
Цитата Сообщение от КОП Посмотреть сообщение
заменить на uint и вообще не надо будет проверять
Проверку на "меньше нуля" я привёл в примере для простоты, в реале там сложное условие.
0
186 / 164 / 100
Регистрация: 14.03.2018
Сообщений: 426
08.09.2018, 20:03 6
Пожалуй, вариант с выбрасыванием исключения, неоднократно предложенный выше, будет оптимальным, но, если по каким-либо причинам он не подходит, можно воспользоваться статическим методом, проверяющим предусловия и создающим экземпляр:
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
    class SomeClass
    {
        private int someField;
 
        public static SomeClass GetInstance(int value)
        {
            if (value > 0)
            {
                return new SomeClass(value);
            }
 
            return null;
        }  
 
        private SomeClass(int value)
        {
            someField = value;
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            SomeClass instance = SomeClass.GetInstance(5);
 
            instance = SomeClass.GetInstance(-5);
 
            if (instance == null)
                Console.WriteLine("Instance is null");
 
            Console.ReadKey();
        }
    }
Хотя это и не лучшее решение, так как в дальнейшем может привести к исключению NullReferenceException в совершенно неожиданном участке кода.
1
Эксперт .NET
4335 / 1997 / 387
Регистрация: 27.03.2010
Сообщений: 5,450
Записей в блоге: 1
08.09.2018, 20:05 7
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Да, такой вариант я рассматривал. Но мне удобнее по функциям, если бы в таком случае объект не создавался - был равен null.
То что ты хочешь сделать не получится так, чтобы в конструктре срабатывало условие и вместо экземпляра класса ты получал null.

Добавлено через 1 минуту
Цитата Сообщение от VladPVS Посмотреть сообщение
Хотя это и не лучшее решение, так как в дальнейшем может привести к исключению NullReferenceException в совершенно неожиданном участке кода.
Бросать исключения при неверных входных параметрах - нормальное решение. Чтобы такого не случилось, нужно перехватывать исключения и обрабатывать их, а перед передачей входных параметров в такие методы, если они получены через ввод от пользователя или заранее неизвестного источника, то нужно их проверять.

Или используй из моего примера подход с методом bool TryToCreateSomething(out SomeType value).
1
186 / 164 / 100
Регистрация: 14.03.2018
Сообщений: 426
08.09.2018, 20:06 8
Цитата Сообщение от Casper-SC Посмотреть сообщение
Бросать исключения при неверных входных параметрах - нормальное решение.
Однозначно. Я имел ввиду свой пример со статическим методом.
1
Модератор
8612 / 5941 / 1691
Регистрация: 21.04.2018
Сообщений: 17,670
Записей в блоге: 2
08.09.2018, 20:06  [ТС] 9
Цитата Сообщение от Элд Хасп Посмотреть сообщение
...выйти без создания нового объекта...
У меня мысли были по поводу явного-неявного вызова конструктора базового класса. Не совсем понял эту часть.
Да, и в данном случае, вроде, нет базового класса. Или он всё таки по умолчанию есть? Возможно, Object?
Если есть, то как от неявного вызова перейти к явному?
0
186 / 164 / 100
Регистрация: 14.03.2018
Сообщений: 426
08.09.2018, 20:19 10
Все классы и структуры являются наследниками от System.Object.
Для вызова конструктора базового класса используется ключевое слово base:

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
public class MyClass
{
    public int Number { get; }
 
    public MyClass() : base()
    {
    }
 
    public MyClass(int NewNumber) : base()
    {
        if (Number < 0)
        {
            
        }
 
        Number = NewNumber;
    }
}
 
public class DerivedClass : MyClass
{
    private int ownValue;
    public DerivedClass(int ownValue, int baseValue): base(baseValue)
    {
        this.ownValue = ownValue;
    }
}
Если ключевое слово base не указано - будет вызван конструктор без параметров базового класса, если же таковой отсутствует - возникнет ошибка компиляции.
0
Модератор
8612 / 5941 / 1691
Регистрация: 21.04.2018
Сообщений: 17,670
Записей в блоге: 2
08.09.2018, 20:25  [ТС] 11
Цитата Сообщение от VladPVS Посмотреть сообщение
Хотя это и не лучшее решение, так как в дальнейшем...
В конечном итоге у меня это используется в WPF Binding - если нужное число, то отображается, если нет, то пусто. Можно, конечно, этого добиться триггерами, ковертерами, но в данном случае мне проще было бы получать сразу null.

Добавлено через 4 минуты
Цитата Сообщение от VladPVS Посмотреть сообщение
.... от System.Object.
Для вызова конструктора базового класса ...
И этот конструктор в пользовательском классе вызывается всегда? Или можно каким-то образом не вызывать его?
0
КОП
08.09.2018, 20:30
  #12

Не по теме:

Цитата Сообщение от Элд Хасп Посмотреть сообщение
В конечном итоге у меня это используется ...
вот мы и забиваем гвозди микроскопом..

0
186 / 164 / 100
Регистрация: 14.03.2018
Сообщений: 426
08.09.2018, 20:31 13
Да, вызывается, просто неявно.
1
Модератор
8612 / 5941 / 1691
Регистрация: 21.04.2018
Сообщений: 17,670
Записей в блоге: 2
08.09.2018, 20:33  [ТС] 14

Не по теме:

Цитата Сообщение от КОП Посмотреть сообщение
вот мы и забиваем гвозди микроскопом
Ну и с целью обучения, конечно. C# изучаю второй месяц токо.

0
Эксперт .NETАвтор FAQ
9634 / 4749 / 1708
Регистрация: 11.01.2015
Сообщений: 5,926
Записей в блоге: 34
08.09.2018, 22:04 15
Лучший ответ Сообщение было отмечено Элд Хасп как решение

Решение

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Или можно каким-то образом не вызывать его?
Нет, нельзя не вызывать, базовый конструктор вызывается всегда.

И кстати, заметьте, что при выбросе исключения в конструкторе на самом деле объект все равно создается. Вы не сможете получить на него ссылку, это да. Но память под объект будет выделена, и базовые конструкторы все равно вызовутся и отработают (потому что они вызываются ДО вашего конструктора и до выброса исключения).
Поэтому, если у вас условное создание объекта, то я бы делал статическим методом, как описано в посте #6.
К тому же, не стоит забывать, что выброс и отлов исключения - дорогая операция, и использовать исключения для проверки условий - не рекомендуется. Если ваша WPF форма большая, то заполнение формы с многочисленными выбросами исключений, могут замедлить ее работу даже до такого уровня, что это будет заметно на глаз.
1
Модератор
8612 / 5941 / 1691
Регистрация: 21.04.2018
Сообщений: 17,670
Записей в блоге: 2
08.09.2018, 22:17  [ТС] 16
Цитата Сообщение от Storm23 Посмотреть сообщение
то я бы делал статическим методом
У меня так сделано (см. #5 метод Create).
Цитата Сообщение от Storm23 Посмотреть сообщение
Нет, нельзя не вызывать, базовый конструктор вызывается всегда.
Догадывался, но точно не знал. Поэтому и поинтересовался.
0
Эксперт .NETАвтор FAQ
9634 / 4749 / 1708
Регистрация: 11.01.2015
Сообщений: 5,926
Записей в блоге: 34
08.09.2018, 23:05 17
Забыл еще добавить, что вызов исключений в конструкторе может привести к некоторым проблемам, если вы используете неуправляемые ресурсы. Дело в том, что метод Dispose не вызывается, если произошло исключение в конструкторе (аналогично не спасает и конструкция с using). Поэтому, если вы (или базовый класс) уже открыл неуправляемый ресурс, то после вылета исключения, этот ресурс скорее всего останется висеть незакрытым.
Более подробно здесь: http://voloda.bazilisek.net/20... nstructor/

И кроме того, на практике, лучше не делать тяжелые конструкторы со сложной логикой внутри. Это рано или поздно приводит к проблемам.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
У меня так сделано (см. #5 метод Create).
Ок, не заметил сразу.
2
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
08.09.2018, 23:05

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

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

Как вызвать виртуальную функцию из дочернего класса, если она определена и вызывается в конструкторе РОДИТЕЛЬСКОГО класса?
Ну то есть так: есть родительский и дочерний класс, в родительском определен виртуальная функция и...

Инициализация объектов класса в конструкторе другого класса
У меня есть класс Subscriber,в котором есть несколько объектов другого класса Date,мне нужно,чтобы...

В конструкторе вложенного класса инициализируется приватное поле. Потом вызывается функция-метод этого класса и выводит значение этого поля НО НЕ ТО!
Друзья! Почему так? #include &lt;windows.h&gt; #include &lt;iostream&gt; using namespace std; //Вот...


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

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.