404 Not Found

404 Not Found


nginx

Comprehensive Project: Task Manager

Requirements Analysis

We will build a command-line task manager that supports the following features:

The functionality is broken down into seven steps, implemented incrementally.

Class Design: Enums and Data Models

First, define the priority enum and the task entity class.

Example

CSHARP
enum Priority
{
    Low,
    Medium,
    High
}

class Task
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public Priority Priority { get; set; }
    public bool IsCompleted { get; set; }
    public DateTime CreatedAt { get; set; }

    public Task(int id, string title, string description, Priority priority)
    {
        Id = id;
        Title = title;
        Description = description;
        Priority = priority;
        IsCompleted = false;
        CreatedAt = DateTime.Now;
    }

    public override string ToString()
    {
        string status = IsCompleted ? "[x]" : "[ ]";
        return $"{Id,-3} {status} {Priority,-6} {CreatedAt:yyyy-MM-dd} {Title}";
    }
}
▶ Try it Yourself

Collection Storage: TaskManager and CRUD Operations

Use List<Task> to store tasks and implement basic create, read, update, and delete operations.

Example

CSHARP
class TaskManager
{
    private List<Task> tasks = new List<Task>();
    private int nextId = 1;

    public Task AddTask(string title, string description, Priority priority)
    {
        Task task = new Task(nextId++, title, description, priority);
        tasks.Add(task);
        return task;
    }

    public bool RemoveTask(int id)
    {
        Task task = tasks.Find(t => t.Id == id);
        if (task != null)
        {
            tasks.Remove(task);
            return true;
        }
        return false;
    }

    public bool CompleteTask(int id)
    {
        Task task = tasks.Find(t => t.Id == id);
        if (task != null)
        {
            task.IsCompleted = true;
            return true;
        }
        return false;
    }

    public List<Task> GetAllTasks()
    {
        return new List<Task>(tasks);
    }

    public void SortByPriority()
    {
        tasks.Sort((a, b) => b.Priority.CompareTo(a.Priority));
    }
}
▶ Try it Yourself

File Persistence: JSON Serialization and Deserialization

Use System.Text.Json to save the task list to a file and load it back.

Example

CSHARP
using System.Text.Json;

class TaskManager
{
    private List<Task> tasks = new List<Task>();
    private int nextId = 1;
    private const string FilePath = "tasks.json";
    private static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions
    {
        WriteIndented = true
    };

    public string SaveToFile()
    {
        try
        {
            string json = JsonSerializer.Serialize(tasks, jsonOptions);
            File.WriteAllText(FilePath, json);
            return "Save succeeded.";
        }
        catch (Exception ex)
        {
            return $"Save failed: {ex.Message}";
        }
    }

    public string LoadFromFile()
    {
        try
        {
            if (!File.Exists(FilePath))
            {
                return "File does not exist, skipping load.";
            }
            string json = File.ReadAllText(FilePath);
            List<Task>? loaded = JsonSerializer.Deserialize<List<Task>>(json);
            if (loaded != null)
            {
                tasks = loaded;
                nextId = tasks.Count > 0 ? tasks.Max(t => t.Id) + 1 : 1;
            }
            return "Load succeeded.";
        }
        catch (JsonException ex)
        {
            return $"JSON format error: {ex.Message}";
        }
        catch (Exception ex)
        {
            return $"Load failed: {ex.Message}";
        }
    }
}
▶ Try it Yourself

LINQ Queries: Filtering and Aggregation

Use LINQ to implement filtering by priority, querying pending tasks, and generating statistics.

Example

CSHARP
class TaskManager
{
    private List<Task> tasks = new List<Task>();

    public List<Task> FilterByPriority(Priority priority)
    {
        return tasks.Where(t => t.Priority == priority).ToList();
    }

    public List<Task> GetPendingTasks()
    {
        return tasks.Where(t => !t.IsCompleted)
                    .OrderByDescending(t => t.Priority)
                    .ToList();
    }

    public Dictionary<Priority, int> GetStatistics()
    {
        return tasks.GroupBy(t => t.Priority)
                    .ToDictionary(g => g.Key, g => g.Count());
    }

    public int GetCompletedCount()
    {
        return tasks.Count(t => t.IsCompleted);
    }

    public int GetPendingCount()
    {
        return tasks.Count(t => !t.IsCompleted);
    }
}
▶ Try it Yourself
TEXT
Sample statistics output:
High: 2, Medium: 3, Low: 1
Completed: 1, Pending: 5

Async File Saving

Use async/await to implement non-blocking file write operations.

Example

CSHARP
class TaskManager
{
    private List<Task> tasks = new List<Task>();
    private const string FilePath = "tasks.json";
    private static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions
    {
        WriteIndented = true
    };

    public async Task<string> SaveToFileAsync()
    {
        try
        {
            string json = JsonSerializer.Serialize(tasks, jsonOptions);
            await File.WriteAllTextAsync(FilePath, json);
            return "Async save succeeded.";
        }
        catch (UnauthorizedAccessException ex)
        {
            return $"File access denied: {ex.Message}";
        }
        catch (IOException ex)
        {
            return $"IO error: {ex.Message}";
        }
        catch (Exception ex)
        {
            return $"Async save failed: {ex.Message}";
        }
    }

    public async Task<string> LoadFromFileAsync()
    {
        try
        {
            if (!File.Exists(FilePath))
            {
                return "File does not exist, skipping load.";
            }
            string json = await File.ReadAllTextAsync(FilePath);
            List<Task>? loaded = JsonSerializer.Deserialize<List<Task>>(json);
            if (loaded != null)
            {
                tasks = loaded;
                nextId = tasks.Count > 0 ? tasks.Max(t => t.Id) + 1 : 1;
            }
            return "Async load succeeded.";
        }
        catch (JsonException ex)
        {
            return $"JSON format error: {ex.Message}";
        }
        catch (Exception ex)
        {
            return $"Async load failed: {ex.Message}";
        }
    }
}
▶ Try it Yourself

Command-Line Interactive Interface

Use a switch statement to build a command-line menu loop.

Example

CSHARP
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        TaskManager manager = new TaskManager();
        string loadResult = await manager.LoadFromFileAsync();
        Console.WriteLine(loadResult);

        while (true)
        {
            Console.WriteLine("\n===== Task Manager =====");
            Console.WriteLine("1. Add task");
            Console.WriteLine("2. Delete task");
            Console.WriteLine("3. Complete task");
            Console.WriteLine("4. List all tasks");
            Console.WriteLine("5. Filter by priority");
            Console.WriteLine("6. View statistics");
            Console.WriteLine("7. Save to file");
            Console.WriteLine("0. Exit");
            Console.Write("Select: ");
            string? input = Console.ReadLine();

            switch (input)
            {
                case "1":
                    Console.Write("Title: ");
                    string? title = Console.ReadLine() ?? "";
                    Console.Write("Description: ");
                    string? desc = Console.ReadLine() ?? "";
                    Console.Write("Priority (Low/Medium/High): ");
                    string? priStr = Console.ReadLine();
                    if (Enum.TryParse<Priority>(priStr, true, out Priority pri))
                    {
                        Task added = manager.AddTask(title, desc, pri);
                        Console.WriteLine($"Added: {added}");
                    }
                    else
                    {
                        Console.WriteLine("Invalid priority.");
                    }
                    break;
                case "2":
                    Console.Write("Task ID: ");
                    if (int.TryParse(Console.ReadLine(), out int delId))
                    {
                        Console.WriteLine(manager.RemoveTask(delId) ? "Deleted." : "Not found.");
                    }
                    break;
                case "3":
                    Console.Write("Task ID: ");
                    if (int.TryParse(Console.ReadLine(), out int compId))
                    {
                        Console.WriteLine(manager.CompleteTask(compId) ? "Completed." : "Not found.");
                    }
                    break;
                case "4":
                    manager.SortByPriority();
                    foreach (Task t in manager.GetAllTasks())
                    {
                        Console.WriteLine(t);
                    }
                    break;
                case "5":
                    Console.Write("Priority (Low/Medium/High): ");
                    if (Enum.TryParse<Priority>(Console.ReadLine(), true, out Priority filterPri))
                    {
                        foreach (Task t in manager.FilterByPriority(filterPri))
                        {
                            Console.WriteLine(t);
                        }
                    }
                    break;
                case "6":
                    Dictionary<Priority, int> stats = manager.GetStatistics();
                    foreach (var kv in stats)
                    {
                        Console.WriteLine($"{kv.Key}: {kv.Value}");
                    }
                    Console.WriteLine($"Completed: {manager.GetCompletedCount()}, Pending: {manager.GetPendingCount()}");
                    break;
                case "7":
                    string saveResult = await manager.SaveToFileAsync();
                    Console.WriteLine(saveResult);
                    break;
                case "0":
                    string finalSave = await manager.SaveToFileAsync();
                    Console.WriteLine(finalSave);
                    Console.WriteLine("Goodbye!");
                    return;
                default:
                    Console.WriteLine("Invalid selection.");
                    break;
            }
        }
    }
}
▶ Try it Yourself
TEXT
===== Task Manager =====
1. Add task
2. Delete task
3. Complete task
4. List all tasks
5. Filter by priority
6. View statistics
7. Save to file
0. Exit
Select: 1
Title: Learn C#
Description: Complete lesson 36
Priority (Low/Medium/High): High
Added: 1   [ ] High   2026-06-28 Learn C#

Project Structure Organization

Use namespaces and using to organize code, placing different responsibilities in separate files.

Example

Project file structure:

TEXT
TaskManagerApp/
├── Models/
│   ├── Priority.cs
│   └── Task.cs
├── Services/
│   └── TaskManager.cs
└── Program.cs
▶ Try it Yourself

Priority.cs:

CSHARP
namespace TaskManagerApp.Models
{
    public enum Priority
    {
        Low,
        Medium,
        High
    }
}

Task.cs:

CSHARP
using System;

namespace TaskManagerApp.Models
{
    public class Task
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public Priority Priority { get; set; }
        public bool IsCompleted { get; set; }
        public DateTime CreatedAt { get; set; }

        public Task(int id, string title, string description, Priority priority)
        {
            Id = id;
            Title = title;
            Description = description;
            Priority = priority;
            IsCompleted = false;
            CreatedAt = DateTime.Now;
        }

        public override string ToString()
        {
            string status = IsCompleted ? "[x]" : "[ ]";
            return $"{Id,-3} {status} {Priority,-6} {CreatedAt:yyyy-MM-dd} {Title}";
        }
    }
}

TaskManager.cs:

CSHARP
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using TaskManagerApp.Models;

namespace TaskManagerApp.Services
{
    public class TaskManager
    {
        private List<Models.Task> tasks = new List<Models.Task>();
        private int nextId = 1;
        private const string FilePath = "tasks.json";
        private static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions
        {
            WriteIndented = true
        };

        public Models.Task AddTask(string title, string description, Priority priority)
        {
            Models.Task task = new Models.Task(nextId++, title, description, priority);
            tasks.Add(task);
            return task;
        }

        public bool RemoveTask(int id)
        {
            Models.Task? task = tasks.Find(t => t.Id == id);
            if (task != null)
            {
                tasks.Remove(task);
                return true;
            }
            return false;
        }

        public bool CompleteTask(int id)
        {
            Models.Task? task = tasks.Find(t => t.Id == id);
            if (task != null)
            {
                task.IsCompleted = true;
                return true;
            }
            return false;
        }

        public List<Models.Task> GetAllTasks()
        {
            return new List<Models.Task>(tasks);
        }

        public void SortByPriority()
        {
            tasks.Sort((a, b) => b.Priority.CompareTo(a.Priority));
        }

        public List<Models.Task> FilterByPriority(Priority priority)
        {
            return tasks.Where(t => t.Priority == priority).ToList();
        }

        public List<Models.Task> GetPendingTasks()
        {
            return tasks.Where(t => !t.IsCompleted)
                        .OrderByDescending(t => t.Priority)
                        .ToList();
        }

        public Dictionary<Priority, int> GetStatistics()
        {
            return tasks.GroupBy(t => t.Priority)
                        .ToDictionary(g => g.Key, g => g.Count());
        }

        public int GetCompletedCount()
        {
            return tasks.Count(t => t.IsCompleted);
        }

        public int GetPendingCount()
        {
            return tasks.Count(t => !t.IsCompleted);
        }

        public async Task<string> SaveToFileAsync()
        {
            try
            {
                string json = JsonSerializer.Serialize(tasks, jsonOptions);
                await File.WriteAllTextAsync(FilePath, json);
                return "Save succeeded.";
            }
            catch (UnauthorizedAccessException ex)
            {
                return $"Access denied: {ex.Message}";
            }
            catch (IOException ex)
            {
                return $"IO error: {ex.Message}";
            }
            catch (Exception ex)
            {
                return $"Save failed: {ex.Message}";
            }
        }

        public async Task<string> LoadFromFileAsync()
        {
            try
            {
                if (!File.Exists(FilePath))
                {
                    return "File does not exist, skipping load.";
                }
                string json = await File.ReadAllTextAsync(FilePath);
                List<Models.Task>? loaded = JsonSerializer.Deserialize<List<Models.Task>>(json);
                if (loaded != null)
                {
                    tasks = loaded;
                    nextId = tasks.Count > 0 ? tasks.Max(t => t.Id) + 1 : 1;
                }
                return "Load succeeded.";
            }
            catch (JsonException ex)
            {
                return $"JSON format error: {ex.Message}";
            }
            catch (Exception ex)
            {
                return $"Load failed: {ex.Message}";
            }
        }
    }
}

Program.cs:

CSHARP
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TaskManagerApp.Models;
using TaskManagerApp.Services;

namespace TaskManagerApp
{
    class Program
    {
        static async Task Main()
        {
            TaskManager manager = new TaskManager();
            string loadResult = await manager.LoadFromFileAsync();
            Console.WriteLine(loadResult);

            while (true)
            {
                Console.WriteLine("\n===== Task Manager =====");
                Console.WriteLine("1. Add task");
                Console.WriteLine("2. Delete task");
                Console.WriteLine("3. Complete task");
                Console.WriteLine("4. List all tasks");
                Console.WriteLine("5. Filter by priority");
                Console.WriteLine("6. View statistics");
                Console.WriteLine("7. Save to file");
                Console.WriteLine("0. Exit");
                Console.Write("Select: ");
                string? input = Console.ReadLine();

                switch (input)
                {
                    case "1":
                        Console.Write("Title: ");
                        string? title = Console.ReadLine() ?? "";
                        Console.Write("Description: ");
                        string? desc = Console.ReadLine() ?? "";
                        Console.Write("Priority (Low/Medium/High): ");
                        string? priStr = Console.ReadLine();
                        if (Enum.TryParse<Priority>(priStr, true, out Priority pri))
                        {
                            Models.Task added = manager.AddTask(title, desc, pri);
                            Console.WriteLine($"Added: {added}");
                        }
                        else
                        {
                            Console.WriteLine("Invalid priority.");
                        }
                        break;
                    case "2":
                        Console.Write("Task ID: ");
                        if (int.TryParse(Console.ReadLine(), out int delId))
                        {
                            Console.WriteLine(manager.RemoveTask(delId) ? "Deleted." : "Not found.");
                        }
                        break;
                    case "3":
                        Console.Write("Task ID: ");
                        if (int.TryParse(Console.ReadLine(), out int compId))
                        {
                            Console.WriteLine(manager.CompleteTask(compId) ? "Completed." : "Not found.");
                        }
                        break;
                    case "4":
                        manager.SortByPriority();
                        foreach (Models.Task t in manager.GetAllTasks())
                        {
                            Console.WriteLine(t);
                        }
                        break;
                    case "5":
                        Console.Write("Priority (Low/Medium/High): ");
                        if (Enum.TryParse<Priority>(Console.ReadLine(), true, out Priority filterPri))
                        {
                            foreach (Models.Task t in manager.FilterByPriority(filterPri))
                            {
                                Console.WriteLine(t);
                            }
                        }
                        break;
                    case "6":
                        Dictionary<Priority, int> stats = manager.GetStatistics();
                        foreach (var kv in stats)
                        {
                            Console.WriteLine($"{kv.Key}: {kv.Value}");
                        }
                        Console.WriteLine($"Completed: {manager.GetCompletedCount()}, Pending: {manager.GetPendingCount()}");
                        break;
                    case "7":
                        string saveResult = await manager.SaveToFileAsync();
                        Console.WriteLine(saveResult);
                        break;
                    case "0":
                        string finalSave = await manager.SaveToFileAsync();
                        Console.WriteLine(finalSave);
                        Console.WriteLine("Goodbye!");
                        return;
                    default:
                        Console.WriteLine("Invalid selection.");
                        break;
                }
            }
        }
    }
}

Complete Single-File Version

Merge all code into a single compilable file for quick testing.

Example

CSHARP
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

enum Priority
{
    Low,
    Medium,
    High
}

class Task
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public Priority Priority { get; set; }
    public bool IsCompleted { get; set; }
    public DateTime CreatedAt { get; set; }

    public Task(int id, string title, string description, Priority priority)
    {
        Id = id;
        Title = title;
        Description = description;
        Priority = priority;
        IsCompleted = false;
        CreatedAt = DateTime.Now;
    }

    public override string ToString()
    {
        string status = IsCompleted ? "[x]" : "[ ]";
        return $"{Id,-3} {status} {Priority,-6} {CreatedAt:yyyy-MM-dd} {Title}";
    }
}

class TaskManager
{
    private List<Task> tasks = new List<Task>();
    private int nextId = 1;
    private const string FilePath = "tasks.json";
    private static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions
    {
        WriteIndented = true
    };

    public Task AddTask(string title, string description, Priority priority)
    {
        Task task = new Task(nextId++, title, description, priority);
        tasks.Add(task);
        return task;
    }

    public bool RemoveTask(int id)
    {
        Task? task = tasks.Find(t => t.Id == id);
        if (task != null)
        {
            tasks.Remove(task);
            return true;
        }
        return false;
    }

    public bool CompleteTask(int id)
    {
        Task? task = tasks.Find(t => t.Id == id);
        if (task != null)
        {
            task.IsCompleted = true;
            return true;
        }
        return false;
    }

    public List<Task> GetAllTasks()
    {
        return new List<Task>(tasks);
    }

    public void SortByPriority()
    {
        tasks.Sort((a, b) => b.Priority.CompareTo(a.Priority));
    }

    public List<Task> FilterByPriority(Priority priority)
    {
        return tasks.Where(t => t.Priority == priority).ToList();
    }

    public List<Task> GetPendingTasks()
    {
        return tasks.Where(t => !t.IsCompleted)
                    .OrderByDescending(t => t.Priority)
                    .ToList();
    }

    public Dictionary<Priority, int> GetStatistics()
    {
        return tasks.GroupBy(t => t.Priority)
                    .ToDictionary(g => g.Key, g => g.Count());
    }

    public int GetCompletedCount()
    {
        return tasks.Count(t => t.IsCompleted);
    }

    public int GetPendingCount()
    {
        return tasks.Count(t => !t.IsCompleted);
    }

    public async Task<string> SaveToFileAsync()
    {
        try
        {
            string json = JsonSerializer.Serialize(tasks, jsonOptions);
            await File.WriteAllTextAsync(FilePath, json);
            return "Save succeeded.";
        }
        catch (UnauthorizedAccessException ex)
        {
            return $"Access denied: {ex.Message}";
        }
        catch (IOException ex)
        {
            return $"IO error: {ex.Message}";
        }
        catch (Exception ex)
        {
            return $"Save failed: {ex.Message}";
        }
    }

    public async Task<string> LoadFromFileAsync()
    {
        try
        {
            if (!File.Exists(FilePath))
            {
                return "File does not exist, skipping load.";
            }
            string json = await File.ReadAllTextAsync(FilePath);
            List<Task>? loaded = JsonSerializer.Deserialize<List<Task>>(json);
            if (loaded != null)
            {
                tasks = loaded;
                nextId = tasks.Count > 0 ? tasks.Max(t => t.Id) + 1 : 1;
            }
            return "Load succeeded.";
        }
        catch (JsonException ex)
        {
            return $"JSON format error: {ex.Message}";
        }
        catch (Exception ex)
        {
            return $"Load failed: {ex.Message}";
        }
    }
}

class Program
{
    static async Task Main()
    {
        TaskManager manager = new TaskManager();
        string loadResult = await manager.LoadFromFileAsync();
        Console.WriteLine(loadResult);

        while (true)
        {
            Console.WriteLine("\n===== Task Manager =====");
            Console.WriteLine("1. Add task");
            Console.WriteLine("2. Delete task");
            Console.WriteLine("3. Complete task");
            Console.WriteLine("4. List all tasks");
            Console.WriteLine("5. Filter by priority");
            Console.WriteLine("6. View statistics");
            Console.WriteLine("7. Save to file");
            Console.WriteLine("0. Exit");
            Console.Write("Select: ");
            string? input = Console.ReadLine();

            switch (input)
            {
                case "1":
                    Console.Write("Title: ");
                    string? title = Console.ReadLine() ?? "";
                    Console.Write("Description: ");
                    string? desc = Console.ReadLine() ?? "";
                    Console.Write("Priority (Low/Medium/High): ");
                    string? priStr = Console.ReadLine();
                    if (Enum.TryParse<Priority>(priStr, true, out Priority pri))
                    {
                        Task added = manager.AddTask(title, desc, pri);
                        Console.WriteLine($"Added: {added}");
                    }
                    else
                    {
                        Console.WriteLine("Invalid priority.");
                    }
                    break;
                case "2":
                    Console.Write("Task ID: ");
                    if (int.TryParse(Console.ReadLine(), out int delId))
                    {
                        Console.WriteLine(manager.RemoveTask(delId) ? "Deleted." : "Not found.");
                    }
                    break;
                case "3":
                    Console.Write("Task ID: ");
                    if (int.TryParse(Console.ReadLine(), out int compId))
                    {
                        Console.WriteLine(manager.CompleteTask(compId) ? "Completed." : "Not found.");
                    }
                    break;
                case "4":
                    manager.SortByPriority();
                    foreach (Task t in manager.GetAllTasks())
                    {
                        Console.WriteLine(t);
                    }
                    break;
                case "5":
                    Console.Write("Priority (Low/Medium/High): ");
                    if (Enum.TryParse<Priority>(Console.ReadLine(), true, out Priority filterPri))
                    {
                        foreach (Task t in manager.FilterByPriority(filterPri))
                        {
                            Console.WriteLine(t);
                        }
                    }
                    break;
                case "6":
                    Dictionary<Priority, int> stats = manager.GetStatistics();
                    foreach (var kv in stats)
                    {
                        Console.WriteLine($"{kv.Key}: {kv.Value}");
                    }
                    Console.WriteLine($"Completed: {manager.GetCompletedCount()}, Pending: {manager.GetPendingCount()}");
                    break;
                case "7":
                    string saveResult = await manager.SaveToFileAsync();
                    Console.WriteLine(saveResult);
                    break;
                case "0":
                    string finalSave = await manager.SaveToFileAsync();
                    Console.WriteLine(finalSave);
                    Console.WriteLine("Goodbye!");
                    return;
                default:
                    Console.WriteLine("Invalid selection.");
                    break;
            }
        }
    }
}
▶ Try it Yourself
TEXT
Load succeeded.

===== Task Manager =====
1. Add task
2. Delete task
3. Complete task
4. List all tasks
5. Filter by priority
6. View statistics
7. Save to file
0. Exit
Select: 1
Title: Learn C#
Description: Complete lesson 36
Priority (Low/Medium/High): High
Added: 1   [ ] High   2026-06-28 Learn C#

Select: 1
Title: Write documentation
Description: Organize project docs
Priority (Low/Medium/High): Medium
Added: 2   [ ] Medium 2026-06-28 Write documentation

Select: 3
Task ID: 2
Completed.

Select: 4
2   [x] Medium 2026-06-28 Write documentation
1   [ ] High   2026-06-28 Learn C#

Select: 6
High: 1
Medium: 1
Completed: 1, Pending: 1

Select: 0
Save succeeded.
Goodbye!

❓ FAQ

Q Why does serialization require a parameterless constructor?
A System.Text.Json requires one by default; you can bypass this by customizing a converter via JsonSerializerOptions.
Q What happens when List.Find doesn't find an element?
A Find returns null without throwing an exception; always check for null before using the result.
Q What happens if an async method lacks an await?
A The task becomes "fire and forget" — exceptions won't be caught, potentially causing data loss.
Q What does Enum.TryParse return on failure?
A It returns false, the output parameter keeps its default value, and no exception is thrown.

📖 Summary

📝 Exercises

  1. Add a DueDate property to the Task class and implement a "show overdue tasks" feature
  2. Add an EditTask method to TaskManager that supports modifying the title and description
  3. Change the save format from JSON to CSV, implementing your own serialization logic
  4. Add sorting by creation date and searching by title
  5. Implement a command-line argument mode: the program executes an operation via args at startup and then exits
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏