diff --git a/CSharpEducation.sln b/CSharpEducation.sln index 6b4d357..212d885 100644 --- a/CSharpEducation.sln +++ b/CSharpEducation.sln @@ -9,7 +9,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Task2", "Task2\Task2.csproj EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Practice", "Practice\Practice.csproj", "{F5E2E1BD-7248-4069-B991-520505CFDDC1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Task3", "Task3\Task3.csproj", "{70A7F1E7-2B00-4244-A0E2-55D56FDD0DB1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Task3", "Task3\Task3.csproj", "{70A7F1E7-2B00-4244-A0E2-55D56FDD0DB1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Task4", "Task4\Task4.csproj", "{9029EB45-ABCC-4879-9802-06FB2702E70F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -33,6 +35,10 @@ Global {70A7F1E7-2B00-4244-A0E2-55D56FDD0DB1}.Debug|Any CPU.Build.0 = Debug|Any CPU {70A7F1E7-2B00-4244-A0E2-55D56FDD0DB1}.Release|Any CPU.ActiveCfg = Release|Any CPU {70A7F1E7-2B00-4244-A0E2-55D56FDD0DB1}.Release|Any CPU.Build.0 = Release|Any CPU + {9029EB45-ABCC-4879-9802-06FB2702E70F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9029EB45-ABCC-4879-9802-06FB2702E70F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9029EB45-ABCC-4879-9802-06FB2702E70F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9029EB45-ABCC-4879-9802-06FB2702E70F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index 46f813d..85cbd2b 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,43 @@ ## Task1 Создать проект консольногно приложения и вывести на экран "Hello, World!". + ## Task2 ### Игра "Крестики-нолики" - Реализовано на классах - Можно менять размер поля - Навигация по полю кнопками со стрелками + + +## Task3 +### PhoneBook +Текст задания: +* Должна быть реализована CRUD функциональность: + + Должен уметь принимать от пользователя номер и имя телефона. + + Сохранять номер в файле phonebook.txt. (При завершении программы либо при добавлении). + + Вычитывать из файла сохранённые номера. (При старте программы). + + Удалять номера. + + Получать абонента по номеру телефона. + + Получать номер телефона по имени абонента. +* Обращение к Phonebook должно быть как к классу-одиночке. +* Внутри должна быть коллекция с абонентами. +* Для обращения с абонентами нужно завести класс Abonent. С полями «номер телефона», «имя». +* Не дать заносить уже записанного абонента. + + +## Task4 +### Репозиторий сущностей +Текст задания: +1. Создайте интерфейс IRepository для базовых операций с сущностями (CRUD) +2. Добавьте ограничение типа T интерфейсом IEntity +3. Создайте три реализации репозитория: для работы со списком сущностей в памяти, для работы с БД (саму БД можно не реализовывать), и для работы с файлами + + +## Task5 +### Приложение для асинхронной загрузки файлов +Текст задания: приложение, которое загружает файлы из интернета и сохраняет их на локальном компьютере. Пользователь должен иметь возможность ввести URL-адрес файла и выбрать путь для сохранения. Решение должно использовать асинхронный код для выполнения загрузки и сохранения файлов. + + +## Task6 +### Тесты для Phonebook +Текст задания: Написать unit-тесты для проекта Phonebook diff --git a/Task4/DataBaseRepo.cs b/Task4/DataBaseRepo.cs new file mode 100644 index 0000000..02e0f15 --- /dev/null +++ b/Task4/DataBaseRepo.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Task4 +{ + internal class DataBaseRepo : IRepository where T : IEntity, new() + { + #region Поля + private readonly string connectionString; + #endregion + + #region Методы + public void Create(T entity) + { + using (SqlConnection connection = new SqlConnection(this.connectionString)) + { + connection.Open(); + SqlCommand command = new SqlCommand(); + command.CommandText = $"INSERT INTO {connection.Database}(Id, Name, Age) VALUES({entity.Id}, {entity.Name}, {entity.Age})"; + command.Connection = connection; + command.ExecuteNonQuery(); + } + } + + public T Read(string id) + { + T entity = new T(); + + using (SqlConnection connection = new SqlConnection(this.connectionString)) + { + connection.Open(); + SqlCommand command = new SqlCommand(); + command.CommandText = $"SELECT Id, Name, Age FROM {connection.Database} WHERE Id='{id}'"; + command.Connection = connection; + + using (SqlDataReader reader = command.ExecuteReader()) + { + if (reader.HasRows) + { + while (reader.Read()) + { + var Id = reader.GetString(0); + var name = reader.GetString(1); + var age = reader.GetInt32(2); + + entity.Id = Id; + entity.Name = name; + entity.Age = age; + } + } + } + } + return entity; + + } + + public void Update(T entity) + { + using (SqlConnection connection = new SqlConnection(this.connectionString)) + { + connection.Open(); + SqlCommand command = new SqlCommand(); + command.CommandText = $"UPDATE {connection.Database} SET Age={entity.Age}, Name='{entity.Name}' WHERE Id='{entity.Id}'"; + command.Connection = connection; + command.ExecuteNonQuery(); + } + } + + public void Delete(string id) + { + using (SqlConnection connection = new SqlConnection(this.connectionString)) + { + connection.Open(); + SqlCommand command = new SqlCommand(); + command.CommandText = $"DELETE FROM {connection.Database} WHERE Id='{id}'"; + command.Connection = connection; + command.ExecuteNonQuery(); + } + } + #endregion + + #region Конструкторы + public DataBaseRepo(string connectionString) + { + this.connectionString = connectionString; + } + #endregion + } +} diff --git a/Task4/EntityListRepo.cs b/Task4/EntityListRepo.cs new file mode 100644 index 0000000..15ebff6 --- /dev/null +++ b/Task4/EntityListRepo.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace Task4 +{ + internal class EntityListRepo : IRepository where T : IEntity + { + #region Свойства + public List Storage { get; set; } + #endregion + + #region Методы + public void Create(T entity) + { + this.Storage.Add(entity); + } + + public T Read(string id) + { + return this.Storage.Find(e => e.Id == id); + } + + public void Update(T entity) + { + Storage[Storage.FindIndex(e => e.Id == entity.Id)] = entity; + } + + public void Delete(string id) + { + if (!Storage.Remove(Storage.Find(e => e.Id == id))) + { + throw new Exception("Удаление не произошло: сущность не обнаружена в памяти"); + return; + } + } + #endregion + + #region Конструкторы + public EntityListRepo(List storage) + { + this.Storage = storage; + } + #endregion + } +} diff --git a/Task4/FileRepo.cs b/Task4/FileRepo.cs new file mode 100644 index 0000000..1eaaa7f --- /dev/null +++ b/Task4/FileRepo.cs @@ -0,0 +1,98 @@ +using System.IO; +using System.Text.Json; + +namespace Task4 +{ + public class FileRepo : IRepository where T : IEntity, IDisposable + { + #region Поля + private readonly string filepath; + private EntityListRepo fileData; + private bool disposed = false; + private DateTime lastWriteTime; + #endregion + + #region Методы + #region CRUD + public void Create(T entity) + { + UpdateFileDataWhenChanged(); + + this.fileData.Create(entity); + } + + public T Read(string id) + { + UpdateFileDataWhenChanged(); + + return this.fileData.Read(id); + } + + public void Update(T entity) + { + UpdateFileDataWhenChanged(); + + this.fileData.Update(entity); + } + + public void Delete(string id) + { + UpdateFileDataWhenChanged(); + + this.fileData.Delete(id); + } + #endregion + + private void UpdateFileDataWhenChanged() + { + if (IsFileChanged()) + SetFileData(); + } + + private void SetFileData() + { + var data = JsonSerializer.Deserialize>(File.ReadAllText(this.filepath)); + this.fileData = new EntityListRepo(data); + } + + private bool IsFileChanged() + { + + var fileInfo = new FileInfo(this.filepath); + return fileInfo.LastWriteTime != this.lastWriteTime; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposed) return; + if (disposing) + { + File.WriteAllText(this.filepath, JsonSerializer.Serialize(this.fileData)); + this.lastWriteTime = DateTime.Now; + } + disposed = true; + } + #endregion + + #region Конструкторы + public FileRepo(string filepath) + { + this.filepath = filepath; + SetFileData(); + } + #endregion + + #region Деструкторы + ~FileRepo() + { + Dispose(false); + } + #endregion + } +} \ No newline at end of file diff --git a/Task4/IEntity.cs b/Task4/IEntity.cs new file mode 100644 index 0000000..79987bd --- /dev/null +++ b/Task4/IEntity.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Task4 +{ + public interface IEntity + { + // Например зададим следующие свойства. + string Id { get; set; } + string Name { get; set; } + int Age { get; set; } + } +} diff --git a/Task4/IRepository.cs b/Task4/IRepository.cs new file mode 100644 index 0000000..2cfd636 --- /dev/null +++ b/Task4/IRepository.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Task4 +{ + public interface IRepository where T : IEntity + { + void Create(T entity); + T Read(string id); + void Update(T entity); + void Delete(string id); + } +} diff --git a/Task4/Task4.csproj b/Task4/Task4.csproj new file mode 100644 index 0000000..db909ea --- /dev/null +++ b/Task4/Task4.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + +