Пользовательский формат даты и времени

Как и в случае с числовыми данными, для даты и времени можно определять пользовательский формат. Для этого используются специальные символы, которые наведены в таблице 4 (на примере даты 30.06.2014 22:30:10.1234):

Таблица 4

Специальный символ Значениe Результат
y Год 0-9
yy Год 00-99
yyyy Год, 4 цифры
M Месяц 1-12
MM Месяц 01-12
d День 1-31
dd День 01-31
h Час 1-12
hh Час 01-12
H Час 1-24
H Час 01-24
m Минута 0-59
mm Минута 00-59
s Секунда 0-59
ss Секунда 00-59
f – ffffff Доли секунды 12 (для ff)
F-FFFFFF Доли секунды, если они не равны 0 12 (для ff)
MMM Сокращенное имя месяца Июн
MMMM Имя месяца Июнь
ddd Сокращенное имя дня недели Пн
dddd Имя дня недели понедельник
tt Маркер для "AM" и "PM" 12-часового формата PM
zz Смещение временной зоны, короткое +03
zzz Смещение временной зоны, полное +03:00
gg Эра A.D.
: Разделитель времени 22:30:10
/ Разделитель даты 30.06.2014
\ Экранирование  


Пример использования пользовательских форматов даты и времени:

Console.WriteLine("{0:y yy yyy yyyy}", DateTime.Now); // "14 14 2014 2014"
Console.WriteLine("{0:d dd ddd dddd}", DateTime.Now); // "30 30 Пн понедельник"
Console.WriteLine("{0:M MM MMM}", DateTime.Now); // "6 06 Июн"
Console.WriteLine("{0:HH.mm.ss dd-MMM-yyyy}", DateTime.Now); // "03.21.22 30-Июн-2014"
Console.WriteLine("{0:z zz zzz}", DateTime.Now); // "+3 +03 +03:00"

Форматирование с использованием метода ToString

Все правила форматирования, описанные выше, могут быть использованы в перегруженном методе ToString для чисел и дат:

Console.WriteLine(DateTime.Now.ToString("dd MMM yyyy")); // 30 Июн 2014

Региональные параметры CultureInfo

В примерах выше стандартные параметры культуры. Деньги выводились в рублях, названия месяцев, дней на русском языке. CultureInfo также влияет на разделитель в числах, количество символов после точки по умолчанию и другое. Иногда возникает потребность изменить это, и для этого используется CultureInfo. По умолчанию CultureInfo соответствует настройкам Windows (например российские региональные настройки). Чтобы задать собственную культуру при форматировании, используя метод Format, необходимо в конструктор этого метода первым аргументом передать объект CultureInfo.

В примере ниже текущий день выводится с текущими настройками CultureInfo(российскими), с английскими (английский Соединенных Штатов), и с украинскими:

string formattedString = string.Format(new System.Globalization.CultureInfo("en-US"), "{0:dddd} Money - {1:c}", DateTime.Now, 15);
Console.WriteLine("{0:dddd} Money - {1:c}", DateTime.Now, 15); // "понедельник Money - 15,00 руб."
Console.WriteLine(formattedString); // "Monday Money - $15.00"
formatedString = string.Format(new System.Globalization.CultureInfo("uk-UA"), "{0:dddd} Money - {1:c}", DateTime.Now, 15);
Console.WriteLine(formattedString); // "понеділок Money - 15,00 грн."

Домашнее задание

Есть массив дат (с временем) и массив температур, и они соответствуют друг другу. Температуры в массиве имеют вид в формате: «26.3 27.1 30 24.7 25». Необходимо вывести информацию таким образом:

Июн 30 (Пн) 09:31 > 26,3 °C
Июн 30 (Пн) 10:31 > 27,1 °C
Июн 30 (Пн) 11:31 > 30,0 °C

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

Ссылочные типы и типы значений в Си-шарп. Ключевые слова ref и out

В языке Си-шарп все типы данных делятся на две категории – ссылочные типы, и типы значений. Они отличаются способом хранения в памяти, производительностью и другим. В этом уроке мы поговорим, что это всё означает, а также о передаче параметров в метод по ссылке (ключевые слова ref и out).

Типы значений

Эту категорию также называют структурными типами. Типы значений хранятся в стеке. Стек - это область памяти, которая используется для передачи параметров в методы и хранения определенных в пределах методов локальных переменных. Данные переменной типа значения хранятся в самой переменной.

К типам значений относятся:

- Целочисленные типы (byte, sbyte, char, short, ushort, int, uint, long, ulong);
- Типы с плавающей запятой (float, double);
- Тип decimal;
- Тип bool;
- Пользовательские структуры (struct);
- Перечисления (enum).

Код ниже показывает, что при присвоении значения одной переменной значимого типа другой, дальнейшее изменение одной из переменных не влияет на другую. Так потому, что хранение данных значимого типа происходит в самой переменной:

static void Main(string[] args)
{
int a = 1;
int b = 2;
b = a;
a = 3;
Console.WriteLine(a); // 3
Console.WriteLine(b); // 1
}


Ссылочные типы

Переменная ссылочного типа содержит не данные, а ссылку на них. Сами данные в этом случае уже хранятся в куче. Куча - это область памяти, в которой размещаются управляемые объекты, и работает сборщик мусора. Сборщик мусора освобождает все ресурсы и объекты, которые уже не нужны.

К ссылочным типам относятся:

- Классы (class);
- Интерфейсы (interface);
- Делегаты (delegate);
- Тип object;
- Тип string.

В коде ниже был создан простой класс, в котором есть одно поле типа int. Дальше была проделана такая же процедура, как и в случае выше, только результат уже другой. После присвоения одного объекта другому, они стали указывать на одну и ту же область памяти (меняем b – меняется и a):

class Test
{
public int x;
}
class Program
{
static void Main(string[] args)
{
Test a = new Test();
Test b = new Test();
a.x = 1;
b.x = 2;
b = a; // присвоение ссылки
b.x = 3;
Console.WriteLine(a.x); // 3
Console.WriteLine(b.x); // 3
}
}


Передача параметров в метод по ссылке. Операторы ref и out

В C# значения переменных по-умолчанию передаются по значению (в метод передается локальная копия параметра, который используется при вызове). Это означает, что мы не можем внутри метода изменить параметр из вне:

public static void ChangeValue(object a)
{
a = 2;
}

static void Main(string[] args)
{
int a = 1;
ChangeValue(a);
Console.WriteLine(a); // 1
Console.ReadLine();
}


Чтобы передавать параметры по ссылке, и иметь возможность влиять на внешнюю переменную, используются ключевые слова ref и out.

Ключевое слово ref

Чтобы использовать ref, это ключевое слово стоит указать перед типом параметра в методе, и перед параметром при вызове метода:

public static void ChangeValue(ref int a)
{
a = 2;
}
static void Main(string[] args)
{
int a = 1;
ChangeValue(ref a);
Console.WriteLine(a); // 2
Console.ReadLine();
}


В этом примере мы изменили значение внешней переменной внутри метода.

Особенностью ref является то, что переменная, которую мы передаем в метод, обязательно должна быть проинициализирована значением, иначе компилятор выдаст ошибку «Use of unassigned local variable 'a'». Это является главным отличием ref от out.

Ключевое слово out

Out используется точно таким же образом как и ref, за исключением того, что параметр не обязан быть проинициализирован перед передачей, но при этом в методе переданному параметру обязательно должно быть присвоено новое значение:

public static void ChangeValue(out int a)
{
a = 2;
}
static void Main(string[] args)
{
int a;
ChangeValue(out a);
Console.WriteLine(a); // 2
Console.ReadLine();
}


Если не присвоить новое значение параметру out, мы получим ошибку «The out parameter 'a' must be assigned to before control leaves the current method»

Производительность

Учитывая тот факт, что по умолчанию в метод передаются параметры по значению и создаются их копии в стеке, при использовании сложных типов данных (пользовательские структуры), или если метод вызывается много раз, это плохо скажется на производительности. В таком случае также стоит использовать ключевые слова ref и out.

Если говорить в целом о ссылочных типах и типах значений, то производительность приложения упадет, если использовать только ссылочные типы. На создание переменной ссылочного типа в куче выделяется память под данные, а в стеке под ссылку на эти данные. Для типов значений память выделяется только в стеке. Время на размещение данных в стеке меньше, чем в куче, это также идет в плюс типам значений в плане производительности.

Наши рекомендации