Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Добрый день.
- Так как при сдаче работ часто возникают одни и те ошибки, высылаю список
- типичных недочетов и рекомендаций. Если что-ли из перечисленного вам пока не
- понятно, то либо можете изучить это самостоятельно, либо подождать, пока это
- вам объяснят на лекции.
- 1. "Если в лабораторной работе необходимо изменять(!) строку, необходимо
- использовать класс StringBuilder" - если строку не изменяете, StringBuilder
- использовать не надо! Не надо "добавлю на всякий случай StringBuilder, а то
- вдруг не примет"!
- string s = "lorem ipsum";
- // просто берем символ из строки, строка при этом никак не изменится,
- // нет необходимости использовать StringBuilder
- char ch = s[5];
- // заменить символ у строки не получится, т.к. строки неизменяемы
- string a = "duck";
- a[0] = 'l';
- // поэтому в данном случае придется использовать StringBuilder
- StringBuilder sb = new StringBuilder("duck");
- sb[0] = 'l';
- Console.WriteLine(sb);
- // Следующие действия "изменяют" строку: исходная строка-объект
- // не изменяется, но в результате операции создается новый объект,
- // в котором будут отражены соответствующие изменения,
- // и этот объект будет присвоен в переменную
- // методы Insert, Remove, Replace, Concat класса string
- // соединение (конкатенция) строк
- string a = "speech";
- string b = "less";
- a = a + b;
- // следует использовать StringBuilder.Append
- sb = new StringBuilder("speech");
- sb.Append("less");
- Console.WriteLine(sb);
- // если же надо присоединять в начало
- string c = "on";
- c = b + c;
- // можно использовать StringBuilder.Insert
- sb = new StringBuilder("on");
- sb.Insert(0, "less");
- Console.WriteLine(sb);
- // если к строке применяется небольшое количество изменяющих операций -
- // то можно обойтись без StringBuilder:
- // допустимо
- string e = "Следующая лекция будет в пятницу 9 марта";
- e = e.Replace("пятницу", "субботу").Replace("9", "3");
- Console.WriteLine(e);
- // чем больше изменяющих операций применяете к строке - тем вероятней
- // ее следует заменить на StringBuilder. Если делаете какие-либо
- // изменения в цикле, однозначно следует использовать StringBuilder:
- // данный код необходимо переписать с использованием StringBuilder!!!
- Random random = new Random();
- string randomString = "";
- for (int i = 0; i < 30; ++i) {
- randomString += (char)('a' + random.Next(26));
- }
- Console.WriteLine(randomString);
- 2. Random.Next включает нижнюю границу и не включает верхнюю. Например,
- Random.Next(5, 9) может генерировать значения 5, 6, 7, 8, а
- Random.Next(4) может генерировать значения 0, 1, 2, 3.
- (Одна из причин, почему верхняя граница не включается, следующая:
- в массиве длины length мы можем обращаться к элементам с индексами
- 0, 1, 2, ..., length-2, length-1. Если метод Next не будет включать верхнюю
- границу, то для получения случайного элемента из массива мы можем написать:
- arr[random.Next(arr.length)]
- Если же метод Next будет включать верхнюю границу, то придется писать:
- arr[random.Next(arr.length - 1)]
- Так как многие программисты могут забывать вычесть эту единицу,
- было решено верхнюю границу не включать.)
- 3. Random - генератор псевдослучайных чисел (подробнее о ГПСЧ можете почитать,
- например, на википедии): последовательность генерируемых случайных значений
- зависит от начального состояния генератора. Два объекта Random с одинаковым
- начальным состоянием будут генерировать одинаковые последовательности значений.
- Конструктор класса Random, принимающий int, позволяет задавать начальное
- состояние генератора. Например:
- Random first = new Random(1408);
- Random second = new Random(1408);
- Console.WriteLine(first.Next(100)); // 30
- Console.WriteLine(first.Next(100)); // 95
- Console.WriteLine(first.Next(100)); // 94
- Console.WriteLine(second.Next(100)); // 30
- Console.WriteLine(second.Next(100)); // 95
- Console.WriteLine(second.Next(100)); // 94
- Конструктор без параметров класса Random задает начальное состояние генератора
- на основе текущего времени. Если создать два объекта Random при помощи
- конструкторов без параметров примерно в один и тот же момент времени, у них
- будет одно и то же начальное состояние. Например:
- Random first = new Random();
- Random second = new Random();
- Console.WriteLine(first.Next(100)); // a
- Console.WriteLine(first.Next(100)); // b
- Console.WriteLine(first.Next(100)); // c
- // будут выведены те же три числа, которые были выведены выше
- Console.WriteLine(second.Next(100)); // a
- Console.WriteLine(second.Next(100)); // b
- Console.WriteLine(second.Next(100)); // c
- Поэтому необходимо создавать один объект класса Random на всю программу и его
- использовать, а не создавать новый объект каждый раз, когда необходимо вызвать
- метод Next.
- 4. В 3 лабораторной работе наличие свойств у класса обязательно. Также крайне
- желательна проверка в методе set свойства на то, что вводятся
- корректные/допустимые значения. Напомню, свойства выглядят вот так:
- public class Student
- {
- private int _age;
- private string _name;
- public int Age
- {
- get { return _age; }
- set { _age = value > 0 ? value : 0; }
- }
- public string Name
- {
- get { return "My name is " + _name; }
- set { _name = value; }
- }
- }
- Автосвойства в 3 работе использовать нельзя. Автосвойства выглядят следующим
- образом:
- public class Person
- {
- public string Name { get; set; }
- }
- 5. Инициализация полей класса должна происходить в конструкторе того же класса,
- в котором эти поля объявлены.
- Например, так делать не рекомендуется:
- public class Human {
- protected int age;
- protected string name;
- public int GetNameLength() {
- return name.Length;
- }
- }
- public class Student : Human {
- private string university;
- private string speciality;
- public Student(int age, string name, string university, string speciality) {
- this.age = age;
- this.name = name;
- this.university = university;
- this.speciality = speciality;
- }
- }
- Поля age и name объявлены в классе Human, а инициализируются в конструкторе
- класса Student. Вместо этого мы должны инициализировать их в конструкторе
- класса Human, а в конструкторе класса Student вызвать конструктор базового
- класса:
- public class Human {
- protected int age;
- protected string name;
- public Human(int age, string name) {
- this.age = age;
- this.name = name;
- }
- }
- public class Student : Human {
- private string university;
- private string speciality;
- public Student(int age, string name, string university, string speciality) : base(age, name) {
- this.university = university;
- this.speciality = speciality;
- }
- }
- Так следует делать как минимум по двум причинам:
- а) Невозможность или сложность работы непосредственно с самим базовым классом:
- // все поля проинициализированы
- Student student = new Student(18, "Петя", "бгуир", "ИиТП");
- // поля age и name не инициализированы, дальнейшая работа с объектом может вести к ошибкам
- Human human = new Human();
- // например, при обращении к name.Length внутри метода GetNameLength() произойдет ошибка
- Console.WriteLine(human.GetNameLength());
- б) В случае наследования от класса Human каких-либо других классов (например,
- Рабочий, Пенсионер, Школьник и т.д.) при использовании первого подхода можно
- забыть проинициализировать поля age и name в конструкторах наследников. При
- использовании второго подхода компилятор "напомнит" их проинициализировать,
- требуя вызвать конструктор базового класса.
- 6. В случае перегрузки конструкторов (данный подход можно использовать и в
- случае перегрузки методов) желательно одну версию конструктора считать
- "базовой", а в остальных версиях вызывать эту "базовую" версию. Это позволит в
- случае необходимости какого-либо изменения вносить изменения только в одном
- конструкторе, остальные изменятся автоматически.
- Рассмотрим на примере:
- public class Student {
- private int age;
- private string name;
- private string university;
- private string speciality;
- public Student(int age, string name, string university, string speciality) {
- this.age = age;
- this.name = name;
- this.university = university;
- this.speciality = speciality;
- }
- public Student(int age, string name, string speciality) {
- this.age = age;
- this.name = name;
- this.university = "БГУИР";
- this.speciality = speciality;
- }
- public Student(int age, string name) {
- this.age = age;
- this.name = name;
- this.university = "БГУИР";
- this.speciality = "ИиТП";
- }
- }
- В данном случае первый конструктор является наиболее "универсальным" -
- позволяет присвоить значения всем полям класса, второй и третий конструктор
- менее "универсальны": второй конструктор задает полю university значение
- "БГУИР" и тем самым не позволяет присваивать различные значения этому полю,
- для третьего конструктора размышления аналогичны второму. Поэтому желательно
- из второго и третьего конструктора вызывать первый:
- public Student(int age, string name, string speciality) : this(age, name, "БГУИР", speciality) { }
- public Student(int age, string name) : this(age, name, "БГУИР", "ИиТП") { }
- Тогда если нам необходимо добавить в конструктор какую-нибудь функциональность
- (например, убрать начальные и конечные пробелы в строках, тем самым
- преобразовав " бгуир " в "бгуир"), достаточно это сделать в одном
- конструкторе, в остальных конструкторах данные изменения применятся
- автоматически:
- public class Student {
- // поля age, name, ...
- public Student(int age, string name, string university, string speciality) {
- this.age = age;
- this.name = name.Trim();
- this.university = university.Trim();
- this.speciality = speciality.Trim();
- }
- public Student(int age, string name, string speciality) : this(age, name, "БГУИР", speciality) { }
- public Student(int age, string name) : this(age, name, "БГУИР", "ИиТП") { }
- public override string ToString() {
- return $"{age} {name} {university} {speciality}";
- }
- }
- public class Program
- {
- public static void Main(string[] args)
- {
- Student student = new Student(18, " Петя ", " бгуир ", " ВМСиС ");
- Console.WriteLine(student); // "18 Петя бгуир ВМСиС"
- student = new Student(19, " Вася ", " ПОИТ ");
- Console.WriteLine(student); // "19 Вася БГУИР ПОИТ"
- student = new Student(21, " Леня ");
- Console.WriteLine(student); // "21 Леня БГУИР ИиТП"
- }
- }
- 7. Желательно не складывать строки при помощи оператора +, лучше использовать
- форматирование (из-за обилия символов " и + затруднительно понять, как должна
- выглядеть результирующая строка).
- string expr;
- int a = 5;
- int b = 7;
- string name = "Вася";
- int age = 18;
- string speciality = "ИиТП";
- // можно, но лучше так не писать
- Console.WriteLine("Я - " + name + ", мне " + age + " лет, я студент специальности " + speciality);
- expr = a + " + " + b + " равно " + (a + b);
- Console.WriteLine(expr);
- // так лучше
- Console.WriteLine("Я - {0}, мне {1} лет, я студент специальности {2}", name, age, speciality);
- expr = string.Format("{0} + {1} равно {2}", a, b, a + b);
- Console.WriteLine(expr);
- // "синтаксический сахар" для string.Format, лаконичней и удобней
- // данное действие называется интерполяцией строк
- expr = $"{a} + {b} равно {a + b}";
- Console.WriteLine(expr);
- 8. Старайтесь не читать с консоли и не писать в консоль в конструкторах и
- методах классов Human, Student и т.д. - работу с консолью следует
- осуществлять в методе Main.
- 9. У многих встречался такой метод:
- public class Student : Human {
- // ...
- public void showInfo() {
- Console.WriteLine($"Имя: {name} Возраст: {age} Университет: {university} Специальность: {speciality}");
- }
- }
- // где-то в методе main выводим информацию на консоль
- student.showInfo();
- Во-первых: метод возвращает void и при этом внутри себя печатает на консоль,
- лучше сделать так, чтобы он возвращал строку, а в методе Main печатаем
- возвращаемое значение на консоль.
- Во-вторых: цель данного метода - преобразовать наш объект в строковое
- представление, для этой цели традиционно используется метод ToString(), поэтому
- ваш метод следует так и назвать.
- В-третьих: данный метод отображает как свои поля, так и поля базового класса,
- лучше в методе отображать поля только текущего класса, для отображения полей
- базового класса лучше вызывать соответствующий метод базового класса.
- С учетом этого данный метод лучше переписать следующим образом:
- public class Human {
- // ...
- public override string ToString() {
- return $"Имя: {name} Возраст: {age}";
- }
- }
- public class Student : Human {
- // ...
- public override string ToString() {
- return $"{base.ToString()} Университет: {university} Специальность: {speciality}";
- }
- }
- // в методе main выводим на консоль
- Student student = new Student(18, "Петя", "бгуир", "ИиТП");
- // здесь неявно вызывается Student.ToString()
- Console.WriteLine(student);
- 10. Если возникает желание кусок кода скопировать с места А в место Б -
- подумайте, может быть лучше этот кусок кода поместить в метод и в местах А и Б
- поместить вызов этого метода.
- 11. Если название переменной, класса, функции и т.д. состоит из нескольких слов,
- первые буквы второго и последующих слов следует делать большими - someLongName,
- но не some_long_name (в некоторых других языках принято так писать, но не в c#)
- и не somelongname.
- Названия классов, методов, свойств следует начинать с большой буквы;
- названия полей, локальных переменных, параметров методов следует начинать с
- маленькой буквы.
- (В примерах кода вы можете увидеть, что названия приватных полей начинают с
- символа _, например _name. Единого мнения, следует ли так делать, нет, поэтому
- данного правила можете не придерживаться.)
- Чтобы быстро переименовать функцию, переменную, класс и т.д. во всех местах,
- достаточно выделить название в одном месте, нажать правой кнопкой мыши,
- выбрать в меню "переименовать", ввести новое название и нажать enter. Во всех
- остальных местах название изменится автоматически.
- 12. Читайте методички - в них всего 83 и 161 страницы, это не Рихтер на 1000+
- страниц. В них в очень краткой форме собрано очень много полезного материала.
- В методичке "Базовые технологии платформы .NET" есть таблицы со статическими и
- экземплярными методами стандартных типов: Contains, IndexOf, IsUpper и т.д.
- Ознакомьтесь с этими таблицами, с тем, что делают эти методы, часто с
- использованием этих методов можно написать более короткий код.
- С уважением,
- Гербик А.И.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement