7_Основные возможности System

Урок 7 : Основные возможности System

О чём этот урок

Пространство имён System содержит базовые инструменты C#: работу со строками, датами, математикой и случайными числами. Всё это используется в повседневном программировании.


1. System.Object - базовый класс всех классов

System.Object (сокращение - object) - корневой класс иерархии типов C#. Каждый класс неявно наследует его, даже если это не написано явно.

Три главных виртуальных метода

class Monster
{
    public string Name;
    public int Level;
}

Monster m = new Monster { Name = "Дракон", Level = 50 };

// ToString() - по умолчанию возвращает имя типа
Console.WriteLine(m.ToString());        // "Monster"
Console.WriteLine(m);                   // тоже вызывает ToString()

// Equals() - по умолчанию сравнивает ссылки
Monster a = new Monster { Name = "Орк" };
Monster b = new Monster { Name = "Орк" };
Console.WriteLine(a.Equals(b));         // false - разные объекты в памяти!

// GetHashCode() - целочисленный хеш объекта
Console.WriteLine(a.GetHashCode());     // некоторое число

Зачем переопределять эти методы?

class Item
{
    public string Name { get; }
    public int Price { get; }

    public Item(string name, int price)
    {
        Name  = name;
        Price = price;
    }

    // Читаемое строковое представление
    public override string ToString()
        => $"[{Name}] - {Price} монет";

    // Логическое равенство по содержимому
    public override bool Equals(object? obj)
    {
        if (obj is not Item other) return false;
        return Name == other.Name && Price == other.Price;
    }

    // GetHashCode должен быть согласован с Equals:
    // если Equals → true, то GetHashCode должен вернуть одно значение
    public override int GetHashCode()
        => HashCode.Combine(Name, Price);
}

Item sword1 = new Item("Меч", 100);
Item sword2 = new Item("Меч", 100);

Console.WriteLine(sword1);              // "[Меч] - 100 монет"
Console.WriteLine(sword1.Equals(sword2)); // true - теперь сравнивает по содержимому

// Корректная работа в коллекциях (Dictionary, HashSet)
var dict = new Dictionary<Item, int>();
dict[sword1] = 1;
Console.WriteLine(dict[sword2]);        // 1 - найдёт по sword2, т.к. Equals и GetHashCode согласованы
Согласованность Equals и GetHashCode

Если переопределяете Equals - всегда переопределяйте GetHashCode. Иначе объекты не будут корректно работать в Dictionary, HashSet и других хеш-структурах.


2. String vs StringBuilder

string в C# - неизменяемый (immutable) тип. Каждая операция изменения создаёт новый объект в памяти.

Обычная строка - это чистовик: каждое «изменение» создаёт новый лист. StringBuilder - черновик: вы пишете, зачёркиваете, добавляете в одном месте. Только когда всё готово - переносите на чистый лист (ToString()).

Проблема с конкатенацией строк в цикле

// МЕДЛЕННО: каждый += создаёт новый объект string
string result = "";
for (int i = 0; i < 10_000; i++)
{
    result += "Hello"; // 10_000 объектов в памяти!
}

StringBuilder - буфер для эффективного построения строк

using System.Text;

// БЫСТРО: StringBuilder меняет один внутренний буфер
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10_000; i++)
{
    sb.Append("Hello");
}
string result = sb.ToString(); // конвертируем в string в конце

Методы StringBuilder

StringBuilder sb = new StringBuilder();

sb.Append("Привет");            // добавить в конец
sb.Append(", ");
sb.Append("мир");
sb.AppendLine("!");             // добавить + перевод строки
sb.Insert(0, ">> ");            // вставить по индексу
sb.Replace("мир", "Unity");     // заменить подстроку
sb.Remove(0, 3);                // удалить символы

Console.WriteLine(sb.Length);   // количество символов
Console.WriteLine(sb.ToString()); // получить готовую строку

Когда что использовать

Ситуация Используйте
Собираете строку в цикле (100+ итераций) StringBuilder
Небольшое число конкатенаций string + $"" или string.Format
Финальный результат для вывода string

3. System.DateTime

DateTime - дата и время

// Текущее время системы
DateTime now   = DateTime.Now;       // локальное время
DateTime utcNow = DateTime.UtcNow;   // UTC время

// Создание конкретной даты
DateTime release = new DateTime(2024, 11, 15, 12, 0, 0); // 15 ноября 2024, 12:00:00

// Форматирование
Console.WriteLine(now.ToString("dd.MM.yyyy HH:mm:ss"));  // 22.02.2026 15:30:00
Console.WriteLine(now.ToString("yyyy-MM-dd"));            // 2026-02-22

// Арифметика дат
DateTime tomorrow   = now.AddDays(1);
DateTime nextMonth  = now.AddMonths(1);
DateTime nextYear   = now.AddYears(1);

TimeSpan diff = release - now;  // разница между датами
Console.WriteLine($"До события: {diff.Days} дней");

// Свойства компонентов
Console.WriteLine(now.Year);     // год
Console.WriteLine(now.Month);    // месяц
Console.WriteLine(now.DayOfWeek);// день недели (например, Saturday)

TimeSpan - промежуток времени

TimeSpan duration = new TimeSpan(2, 30, 0);  // 2 часа 30 минут

// Из секунд
TimeSpan fromSeconds = TimeSpan.FromSeconds(3661);
Console.WriteLine(fromSeconds.Hours);    // 1
Console.WriteLine(fromSeconds.Minutes);  // 1
Console.WriteLine(fromSeconds.Seconds);  // 1

// Форматирование
Console.WriteLine(fromSeconds.ToString(@"hh\:mm\:ss")); // 01:01:01

Что такое UTC?

UTC (Coordinated Universal Time) - мировое время без часовых поясов. Все часовые пояса определяются смещением от UTC.

DateTimeOffset - дата, время и часовой пояс

DateTime не хранит информацию о часовом поясе. DateTimeOffset решает эту проблему: он хранит дату, время и смещение от UTC в одном значении, что делает его надёжным при передаче данных между системами.

// DateTimeOffset хранит смещение явно
DateTimeOffset dto = DateTimeOffset.Now;
Console.WriteLine(dto); // 2026-04-11 15:30:00 +03:00

// Создание с явным смещением
DateTimeOffset moscow = new DateTimeOffset(2026, 4, 11, 15, 0, 0, TimeSpan.FromHours(3));

// Перевод в UTC
DateTimeOffset utc = dto.ToUniversalTime();
Console.WriteLine(utc.Offset); // 00:00:00

// Форматирование со смещением
Console.WriteLine(dto.ToString("yyyy-MM-dd HH:mm:ss zzz")); // 2026-04-11 15:30:00 +03:00
Тип Часовой пояс Когда использовать
DateTime Не хранит Локальные расчёты, отображение в UI
DateTimeOffset Хранит смещение Базы данных, API, передача данных
DateTime.UtcNow Всегда UTC Внутренняя логика, серверы
Рекомендация

При сохранении или передаче дат между системами используйте DateTimeOffset или UTC. DateTime без явного часового пояса может дать неверный результат при работе в разных регионах.


4. System.Math

Статический класс с математическими функциями. Работает с double.

// Основные методы
Math.Abs(-15)         // 15 - абсолютное значение
Math.Max(10, 20)      // 20 - максимум
Math.Min(10, 20)      // 10 - минимум
Math.Clamp(150, 0, 100) // 100 - ограничение в диапазоне [0, 100]

// Округление
Math.Round(3.7)       // 4 - до ближайшего целого
Math.Floor(3.9)       // 3 - вниз (пол)
Math.Ceiling(3.1)     // 4 - вверх (потолок)
Math.Truncate(3.9)    // 3 - отбросить дробную часть

// Степени и корни
Math.Pow(2, 10)       // 1024 - возведение в степень
Math.Sqrt(144)        // 12  - квадратный корень
Math.Cbrt(27)         // 3   - кубический корень

// Тригонометрия (в радианах)
Math.Sin(Math.PI / 2) // 1.0
Math.Cos(0)           // 1.0
double degrees = 45;
double radians = degrees * Math.PI / 180;

// Константы
Math.PI   // 3.14159...
Math.E    // 2.71828...
Math в Unity

В Unity используется Mathf (вариант с float вместо double): Mathf.Clamp, Mathf.Lerp, Mathf.Sin и т.д. Принципы те же, но быстрее для игровых расчётов.


5. System.Random - псевдослучайные числа

Random rng = new Random();           // с системным seed (начальным значением)
Random seeded = new Random(42);      // с фиксированным seed (воспроизводимый результат)

// Целые числа
int d6 = rng.Next(1, 7);            // от 1 до 6 включительно (верхняя граница не включается!)
int percent = rng.Next(0, 101);      // от 0 до 100
int anyInt = rng.Next();             // любое неотрицательное int

// Дробные числа
double d = rng.NextDouble();         // от 0.0 до 1.0 (не включая 1.0)
float f = (float)rng.NextDouble();

// Диапазон float
float range = 2.0f + (float)rng.NextDouble() * 8.0f; // от 2.0 до 10.0

// C# 6+: можно использовать как статический метод
int val = Random.Shared.Next(1, 101); // потокобезопасный глобальный экземпляр
Псевдослучайность

Random - псевдослучайный генератор. Числа определяются начальным значением (seed). С одинаковым seed - одинаковая последовательность. Это полезно для воспроизводимых тестов, но не подходит для криптографии.

// Пример: случайный предмет из списка
List<string> loot = new List<string> { "Меч", "Щит", "Зелье", "Золото" };
string drop = loot[rng.Next(loot.Count)];
Console.WriteLine($"Выпал: {drop}");

// Пример: проверка шанса (30%)
bool triggered = rng.Next(100) < 30;

Итог урока


📋 Перейти к практическим заданиям урока 7

Материалы для дополнительного ознакомления :

Math
StringBuilder
DateTime
Convert