Предыдущая лекция | Следующая лекция | |
---|---|---|
Строки. | Содержание | Общие сведения о подпрограммах. |
Кроме примитивных типов данных в C# есть такой тип как enum или перечисление. Перечисления представляют набор логически связанных констант. Объявление перечисления происходит с помощью оператора enum. Далее идет название перечисления, после которого указывается тип перечисления - он обязательно должен представлять целочисленный тип (byte, int, short, long). Если тип явным образом не указан, то по умолчанию используется тип int. Затем идет список элементов перечисления через запятую:
enum Days
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
enum Time : byte
{
Morning,
Afternoon,
Evening,
Night
}
В примерах выше каждому элементу перечисления присваивается целочисленное значение, причем первый элемент будет иметь значение 0
, второй 1
и так далее. Мы можем также явным образом указать значения элементов, либо указав значение первого элемента:
enum Operation
{
Add = 1, // каждый следующий элемент по умолчанию увеличивается на единицу
Subtract, // этот элемент равен 2
Multiply, // равен 3
Divide // равен 4
}
Но можно и для всех элементов явным образом указать значения:
enum Operation
{
Add = 2,
Subtract = 4,
Multiply = 8,
Divide = 16
}
При этом контанты перечисления могут иметь одинаковые значения, либо даже можно присваивать одной константе значение другой константы:
enum Color
{
White = 1,
Black = 2,
Green = 2,
Blue = White // Blue = 1
}
Каждое перечисление фактически определяет новый тип данных. Затем в программе мы можем определить переменную этого типа и использовать ее:
enum Operation
{
Add = 1,
Subtract,
Multiply,
Divide
}
class Program
{
static void Main(string[] args)
{
Operation op;
op = Operation.Add;
Console.WriteLine(op); // Add
Console.ReadLine();
}
}
В программе мы можем присвоить значение этой переменной. При этом в качестве ее значения должна выступать одна из констант, определенных в данном перечислении. То есть несмотря на то, что каждая константа сопоставляется с определенным числом, мы не можем присвоить ей числовое значение, например, Operation op = 1;. И также если мы будем выводить на консоль значение этой переменной, то мы получим имя константы, а не числовое значение. Если же необходимо получить числовое значение, то следует выполнить приведение к числовому типу:
Operation op;
op = Operation.Multiply;
Console.WriteLine((int)op); // 3
Зачастую переменная перечисления выступает в качестве хранилища состояния, в зависимости от которого производятся некоторые действия. Так, рассмотрим применение перечисления на более реальном примере:
class Program
{
enum Operation
{
Add = 1,
Subtract,
Multiply,
Divide
}
static void MathOp(double x, double y, Operation op)
{
double result = 0.0;
switch (op)
{
case Operation.Add:
result = x + y;
break;
case Operation.Subtract:
result = x - y;
break;
case Operation.Multiply:
result = x * y;
break;
case Operation.Divide:
result = x / y;
break;
}
Console.WriteLine("Результат операции равен {0}", result);
}
static void Main(string[] args)
{
// Тип операции задаем с помощью константы Operation.Add
MathOp(10, 5, Operation.Add);
// Тип операции задаем с помощью константы Operation.Multiply
MathOp(11, 5, Operation.Multiply);
Console.ReadLine();
}
}
Кортежи предоставляют удобный способ для работы с набором значений.
Кортеж представляет набор значений, заключенных в круглые скобки:
var tuple = (5, 10);
В данном случае определен кортеж tuple, который имеет два значения: 5 и 10. В дальнейшем мы можем обращаться к каждому из этих значений через поля с названиями Item[порядковый_номер_поля_в_кортеже]
. Например:
static void Main(string[] args)
{
var tuple = (5, 10);
Console.WriteLine(tuple.Item1); // 5
Console.WriteLine(tuple.Item2); // 10
tuple.Item1 += 26;
Console.WriteLine(tuple.Item1); // 31
Console.Read();
}
В данном случае тип определяется неявно. Но мы ткже можем явным образом указать для переменной кортежа тип:
(int, int) tuple = (5, 10);
Так как кортеж содержит два числа, то в определении типа нам надо указать два числовых типа. Или другой пример определения кортежа:
(string, int, double) person = ("Tom", 25, 81.23);
Первый элемент кортежа в данном случае представляет строку, второй элемент - тип int, а третий - тип double.
Мы также можем дать названия полям кортежа:
var tuple = (count:5, sum:10);
Console.WriteLine(tuple.count); // 5
Console.WriteLine(tuple.sum); // 10
Теперь чтобы обратиться к полям кортежа используются их имена, а не названия Item1 и Item2.
Мы даже можем не использовать переменную для определения всего кортежа, а использовать отдельные переменные для его полей:
static void Main(string[] args)
{
var (name, age) = ("Tom", 23);
Console.WriteLine(name); // Tom
Console.WriteLine(age); // 23
Console.Read();
}
Кортежи могут передаваться в качестве параметров в метод, могут быть возвращаемым результатом функции, либо использоваться иным образом.
Например, одной из распространенных ситуаций является возвращение из функции двух и более значений, в то время как функция можно возвращать только одно значение. И кортежи представляют оптимальный способ для решения этой задачи:
static void Main(string[] args)
{
var tuple = GetValues();
Console.WriteLine(tuple.Item1); // 1
Console.WriteLine(tuple.Item2); // 3
Console.Read();
}
private static (int, int) GetValues()
{
var result = (1, 3);
return result;
}
Здесь определен метод GetValues(), который возвращает кортеж. Кортеж определяется как набор значений, помещенных в круглые скобки. И в данном случае мы возвращаем кортеж из двух элементов типа int, то есть два числа.
Другой пример:
static void Main(string[] args)
{
var tuple = GetNamedValues(new int[]{ 1,2,3,4,5,6,7});
Console.WriteLine(tuple.count);
Console.WriteLine(tuple.sum);
Console.Read();
}
private static (int sum, int count) GetNamedValues(int[] numbers)
{
var result = (sum:0, count: 0);
for (int i=0; i < numbers.Length; i++)
{
result.sum += numbers[i];
result.count++;
}
return result;
}
И также кортеж может передаваться в качестве параметра в метод:
static void Main(string[] args)
{
var (name, age) = GetTuple(("Tom", 23), 12);
Console.WriteLine(name); // Tom
Console.WriteLine(age); // 35
Console.Read();
}
private static (string name, int age) GetTuple((string n, int a) tuple, int x)
{
var result = (name: tuple.n, age: tuple.a + x);
return result;
}
Коллекция, содержащая только отличающиеся элементы, называется множеством (set). В составе .NET имеются два множества — HashSet и SortedSet. Оба они реализуют интерфейс ISet. Класс HashSet содержит неупорядоченный список различающихся элементов, а в SortedSet элементы упорядочены.
Интерфейс ISet предоставляет методы для создания объединения нескольких множеств, пересечения множеств и определения, является ли одно множество надмножеством или подмножеством другого.
Ниже перечислены наиболее употребительные конструкторы, определенные в классе HashSet:
- public HashSet ()
- public HashSet(IEnumerable collection)
- public HashSet(IEqualityCompare comparer)
- public HashSet(IEnumerable collection, IEqualityCompare comparer)
В первой форме конструктора создается пустое множество, а во второй форме — множество, состоящее из элементов указываемой коллекции collection. В третьей форме конструктора допускается указывать способ сравнения с помощью параметра comparer. А в четвертой форме создается множество, состоящее из элементов указываемой коллекции collection, и используется заданный способ сравнения comparer. Имеется также пятая форма конструктора данного класса, в которой допускается инициализировать множество последовательно упорядоченными данными.
В этом классе предоставляется также метод RemoveWhere(), удаляющий из множества элементы, удовлетворяющие заданному условию, или предикату. Помимо свойств, определенных в интерфейсах, которые реализуются в классе HashSet, в него введено дополнительное свойство Comparer, приведенное ниже:
public IEqualityComparer<T> Comparer { get; }
Оно позволяет получать метод сравнения для вызывающего хеш-множества.
Ниже перечислены четыре наиболее часто используемых конструкторов, определенных в классе SortedSet:
- public SortedSet()
- public SortedSet(IEnumerable collection)
- public SortedSet(IComparer comparer)
- public SortedSet(IEnumerable collection, IComparer comparer)
В первой форме конструктора создается пустое множество, а во второй форме — множество, состоящее из элементов указываемой коллекции collection. В третьей форме конструктора допускается указывать способ сравнения с помощью параметра comparer. А в четвертой форме создается множество, состоящее из элементов указываемой коллекции collection, и используется заданный способ сравнения comparer. Имеется также пятая форма конструктора данного класса, в которой допускается инициализировать множество последовательно упорядоченными данными.
В этом классе предоставляется также метод GetViewBetween(), возвращающий часть множества в форме объекта типа SortedSet, метод RemoveWhere(), удаляющий из множества элементы, не удовлетворяющие заданному условию, или предикату, а также метод Reverse(), возвращающий объект типа IEnumerable, который циклически проходит множество в обратном порядке.
Помимо свойств, определенных в интерфейсах, которые реализуются в классе SortedSet, в него введены дополнительные свойства, приведенные ниже:
- public IComparer Comparer { get; }
- public T Max { get; }
- public T Min { get; }
Свойство Comparer получает способ сравнения для вызывающего множества. Свойство Мах получает наибольшее значение во множестве, а свойство Min — наименьшее значение во множестве. Давайте рассмотрим пример использования множеств:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
// Создадим два множества
SortedSet<char> ss = new SortedSet<char>();
SortedSet<char> ss1 = new SortedSet<char>();
ss.Add('A');
ss.Add('B');
ss.Add('C');
ss.Add('Z');
ShowColl(ss, "Первая коллекция: ");
ss1.Add('X');
ss1.Add('Y');
ss1.Add('Z');
ShowColl(ss1, "Вторая коллекция");
ss.SymmetricExceptWith(ss1);
ShowColl(ss,"Исключили разноименность (одинаковые элементы) двух множеств: ");
ss.UnionWith(ss1);
ShowColl(ss, "Объединение множеств: ");
ss.ExceptWith(ss1);
ShowColl(ss, "Вычитание множеств");
Console.ReadLine();
}
static void ShowColl(SortedSet<char> ss, string s)
{
Console.WriteLine(s);
foreach (char ch in ss)
Console.Write(ch + " ");
Console.WriteLine("\n");
}
}
}
Самописанный пример, объединяющий работу перечислений и множеств:
class Program
{
enum Days
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
static void Main(string[] args)
{
HashSet<Days> DaysHashSet = new HashSet<Days>();
DaysHashSet.Add(Days.Friday);
DaysHashSet.Add(Days.Friday);
DaysHashSet.Add(Days.Monday);
foreach (Days DayItem in DaysHashSet)
Console.WriteLine(DayItem);
Console.Write("Press ENTER to continue...");
Console.ReadLine();
}
}
Программа выведет только Friday и Monday. Т.е. дубли в множество не добавляются и при этом никаких ошибок не возникает. Такое поведение может быть полезно при отслеживании состояния какого-то устройства. Периодически опрашивая устройство мы можем устанавливать состояния не проверя установлено уже это состояние или нет.
Для коллекций вообще и для множеств в частности есть методы объединения, пересечения и разности.
С помощью метода Except можно получить разность двух последовательностей:
var DaysHashSet1 = new HashSet<Days>() { Days.Friday, Days.Monday };
var DaysHashSet2 = new HashSet<Days>() { Days.Friday, Days.Sunday };
var ResHashSet = DaysHashSet1.Except(DaysHashSet2);
foreach (Days DayItem in ResHashSet)
Console.WriteLine(DayItem);
Console.Write("Press ENTER to continue...");
Console.ReadLine();
В данном случае из множества DaysHashSet1 убираются все элементы, которые есть в массиве DaysHashSet2. Результатом операции будет один элемент:
Monday
Для получения пересечения последовательностей, то есть общих для обоих наборов элементов, применяется метод Intersect:
string[] soft = { "Microsoft", "Google", "Apple"};
string[] hard = { "Apple", "IBM", "Samsung"};
// пересечение последовательностей
var result = soft.Intersect(hard);
foreach (string s in result)
Console.WriteLine(s);
Так как оба набора имеют только один общий элемент, то соответственно только он и попадет в результирующую выборку:
Apple
Для объединения двух последовательностей используется метод Union. Его результатом является новый набор, в котором имеются элементы, как из первой, так и из второй последовательности. Повторяющиеся элементы добавляются в результат только один раз:
string[] soft = { "Microsoft", "Google", "Apple"};
string[] hard = { "Apple", "IBM", "Samsung"};
// объединение последовательностей
var result = soft.Union(hard);
foreach (string s in result)
Console.WriteLine(s);
Результатом операции будет следующий набор:
Microsoft
Google
Apple
IBM
Samsung
Если же нам нужно простое объединение двух наборов, то мы можем использовать метод Concat:
var result = soft.Concat(hard);
Те элементы, которые встречаются в обоих наборах, дублируются.
Для удаления дублей в наборе используется метод Distinct:
var result = soft.Concat(hard).Distinct();
Последовательное применение методов Concat и Distinct будет подобно действию метода Union.
Для работы с датами и временем в .NET предназначена структура DateTime. Она представляет дату и время от 00:00:00 1 января 0001 года до 23:59:59 31 декабря 9999 года.
Для создания нового объекта DateTime также можно использовать конструктор. Пустой конструктор создает начальную дату:
DateTime date1 = new DateTime();
Console.WriteLine(date1); // 01.01.0001 0:00:00
То есть мы получим минимально возможное значение, которое также можно получить следующим образом:
Console.WriteLine(DateTime.MinValue);
Чтобы задать конкретную дату, нужно использовать один из конструкторов, принимающих параметры:
DateTime date1 = new DateTime(2015, 7, 20); // год - месяц - день
Console.WriteLine(date1); // 20.07.2015 0:00:00
Установка времени:
DateTime date1 = new DateTime(2015, 7, 20, 18, 30, 25); // год - месяц - день - час - минута - секунда
Console.WriteLine(date1); // 20.07.2015 18:30:25
Если необходимо получить текущую время и дату, то можно использовать ряд свойств DateTime:
Console.WriteLine(DateTime.Now);
Console.WriteLine(DateTime.UtcNow);
Console.WriteLine(DateTime.Today);
Консольный вывод:
20.07.2015 11:43:33
20.07.2015 8:43:33
20.07.2015 0:00:00
Свойство DateTime.Now берет текущую дату и время компьютера, DateTime.UtcNow- дата и время относительно времени по Гринвичу (GMT) и DateTime.Today - только текущая дата.
При работе с датами надо учитывать, что по умолчанию для представления дат применяется григорианский календарь. Но что будет, если мы захотим получить день недели для 5 октября 1582 года:
DateTime someDate = new DateTime(1582, 10, 5);
Console.WriteLine(someDate.DayOfWeek);
Консоль выстветит значение Tuesday, то есть вторник. Однако, как может быть известно из истории, впервые переход с юлианского календаря на григорианский состоялся в октябре 1582 года. Тогда после даты 4 октября (четверг) (еще по юлианскому календарю) сразу перешли к 15 октября (пятница)(уже по григорианскому календарю). Таким образом, фактически выкинули 10 дней. То есть после 4 октября шло 15 октября.
В большинстве случаев данный факт вряд ли как-то повлияет на вычисления, однако при работе с очень давними датами данный аспект следует учитывать.
Основные операции со структурой DateTime связаны со сложением или вычитанием дат. Например, надо к некоторой дате прибавить или, наоборот, отнять несколько дней.
Для добавления дат используется ряд методов:
-
Add(TimeSpan value): добавляет к дате значение TimeSpan
-
AddDays(double value): добавляет к текущей дате несколько дней
-
AddHours(double value): добавляет к текущей дате несколько часов
-
AddMinutes(double value): добавляет к текущей дате несколько минут
-
AddMonths(int value): добавляет к текущей дате несколько месяцев
-
AddYears(int value): добавляет к текущей дате несколько лет
Например, добавим к некоторой дате 3 часа:
DateTime date1 = new DateTime(2015, 7, 20, 18, 30, 25); // 20.07.2015 18:30:25
Console.WriteLine(date1.AddHours(3)); // 20.07.2015 21:30:25
Для вычитания дат используется метод Substract(DateTime date):
DateTime date1 = new DateTime(2015, 7, 20, 18, 30, 25); // 20.07.2015 18:30:25
DateTime date2 = new DateTime(2015, 7, 20, 15, 30, 25); // 20.07.2015 15:30:25
Console.WriteLine(date1.Subtract(date2)); // 03:00:00
Здесь даты различаются на три часа, поэтому результатом будет дата "03:00:00".
Метод Substract не имеет возможностей для отдельного вычитания дней, часов и так далее. Но это и не надо, так как мы можем передавать в метод AddDays() и другие методы добавления отрицательные значения:
// вычтем три часа
DateTime date1 = new DateTime(2015, 7, 20, 18, 30, 25); // 20.07.2015 18:30:25
Console.WriteLine(date1.AddHours(-3)); // 20.07.2015 15:30:25
Кроме операций сложения и вычитания еще есть ряд методов форматирования дат:
DateTime date1 = new DateTime(2015, 7, 20, 18, 30, 25);
Console.WriteLine(date1.ToLocalTime()); // 20.07.2015 21:30:25
Console.WriteLine(date1.ToUniversalTime()); // 20.07.2015 15:30:25
Console.WriteLine(date1.ToLongDateString()); // 20 июля 2015 г.
Console.WriteLine(date1.ToShortDateString()); // 20.07.2015
Console.WriteLine(date1.ToLongTimeString()); // 18:30:25
Console.WriteLine(date1.ToShortTimeString()); // 18:30
Метод ToLocalTime() преобразует время UTC в локальное время, добавляя смещение относительно времени по Гринвичу. Метод ToUniversalTime(), наоборот, преобразует локальное время во время UTC, то есть вычитает смещение относительно времени по Гринвичу. Остальные методы преобразуют дату к определенному формату.
Метод ToString() тоже можно использовать для форматирования. По умолчанию для русской культурной среды он возвращает дату в формате ДД.ММ.ГГГГ Ч:ММ:СС
. Но можно задать нужный формат в параметрах:
дата.ToString("dd.MM.yyyy HH:mm:ss");
Описатель | Описание |
---|---|
d | Представляет день месяца от 1 до 31. Одноразрядные числа используются без нуля в начале |
dd | Представляет день месяца от 1 до 31. К одноразрядным числам в начале добавляется ноль |
ddd | Сокращенное название дня недели (пн,вт...) |
dddd | Полное название дня недели (понедельник, вторник...) |
f / fffffff | Представляет миллисекунды. Количество символов f указывает на число разрядов в миллисекундах |
g | Представляет период или эру (например, "н. э.") |
h | Часы в виде от 1 до 12. Часы с одной цифрой не дополняются нулем |
hh | Часы в виде от 01 до 12. Часы с одной цифрой дополняются нулем |
H | Часы в виде от 0 до 23. Часы с одной цифрой не дополняются нулем |
HH | Часы в виде от 0 до 23. Часы с одной цифрой дополняются нулем |
K | Часовой пояс |
m | Минуты от 0 до 59. Минуты с одной цифрой не дополняются начальным нулем |
mm | Минуты от 0 до 59. Минуты с одной цифрой дополняются начальным нулем |
M | Месяц в виде от 1 до 12 |
MM | Месяц в виде от 1 до 12. Месяц с одной цифрой дополняется начальным нулем |
MMM | Сокращенное название месяца |
MMMM | Полное название месяца |
s | Секунды в виде числа от 0 до 59. Секунды с одной цифрой не дополняются начальным нулем |
ss | Секунды в виде числа от 0 до 59. Секунды с одной цифрой дополняются начальным нулем |
t | Первые символы в обозначениях AM и PM |
tt | AM или PM |
y | Представляет год как число из одной или двух цифр. Если год имеет более двух цифр, то в результате отображаются только две младшие цифры |
yy | Представляет год как число из одной или двух цифр. Если год имеет более двух цифр, то в результате отображаются только две младшие цифры. Если год имеет одну цифру, то он дополняется начальным нулем |
yyy | Год из трех цифр |
yyyy | Год из четырех цифр |
yyyyy | Год из пяти цифр. Если в году меньше пяти цифр, то он дополняется начальными нулями |
z | Представляет смещение в часах относительно времени UTC |
zz | Представляет смещение в часах относительно времени UTC. Если смещение представляет одну цифру, то она дополняется начальным нулем. |
Предыдущая лекция | Следующая лекция | |
---|---|---|
Строки. | Содержание | Общие сведения о подпрограммах. |