You are a helpful assistant.
system
Triển khai cấu trúc dữ liệu cây tìm kiếm nhị phân trong C# với các thao tác chèn, xóa và tìm kiếm, bao gồm xử lý lỗi, đo lường hiệu suất, và yêu cầu kiểm tra đơn vị cho tất cả các thao tác.
user
Để triển khai cấu trúc dữ liệu cây tìm kiếm nhị phân (Binary Search Tree - BST) trong C#, bạn cần thực hiện các bước sau:

1. **Định nghĩa lớp Node**: Mỗi nút trong cây sẽ chứa một giá trị và hai con trỏ tới các nút con trái và phải.

2. **Định nghĩa lớp BinarySearchTree**: Lớp này sẽ chứa các phương thức để chèn, xóa và tìm kiếm.

3. **Xử lý lỗi**: Đảm bảo rằng các thao tác xử lý lỗi hợp lý, chẳng hạn như khi chèn giá trị đã tồn tại hoặc xóa giá trị không tồn tại.

4. **Đo lường hiệu suất**: Sử dụng `Stopwatch` để đo thời gian thực hiện các thao tác.

5. **Kiểm tra đơn vị**: Sử dụng một framework như NUnit hoặc MSTest để viết các bài kiểm tra đơn vị cho các thao tác.

Dưới đây là một ví dụ cơ bản về cách triển khai:

```csharp
using System;
using System.Diagnostics;

public class Node
{
    public int Value;
    public Node Left;
    public Node Right;

    public Node(int value)
    {
        Value = value;
        Left = null;
        Right = null;
    }
}

public class BinarySearchTree
{
    private Node root;

    public BinarySearchTree()
    {
        root = null;
    }

    public void Insert(int value)
    {
        root = InsertRec(root, value);
    }

    private Node InsertRec(Node root, int value)
    {
        if (root == null)
        {
            root = new Node(value);
            return root;
        }

        if (value < root.Value)
            root.Left = InsertRec(root.Left, value);
        else if (value > root.Value)
            root.Right = InsertRec(root.Right, value);

        return root;
    }

    public bool Search(int value)
    {
        return SearchRec(root, value);
    }

    private bool SearchRec(Node root, int value)
    {
        if (root == null)
            return false;

        if (root.Value == value)
            return true;

        if (value < root.Value)
            return SearchRec(root.Left, value);

        return SearchRec(root.Right, value);
    }

    public void Delete(int value)
    {
        root = DeleteRec(root, value);
    }

    private Node DeleteRec(Node root, int value)
    {
        if (root == null)
            return root;

        if (value < root.Value)
            root.Left = DeleteRec(root.Left, value);
        else if (value > root.Value)
            root.Right = DeleteRec(root.Right, value);
        else
        {
            if (root.Left == null)
                return root.Right;
            else if (root.Right == null)
                return root.Left;

            root.Value = MinValue(root.Right);
            root.Right = DeleteRec(root.Right, root.Value);
        }

        return root;
    }

    private int MinValue(Node root)
    {
        int minValue = root.Value;
        while (root.Left != null)
        {
            minValue = root.Left.Value;
            root = root.Left;
        }
        return minValue;
    }
}

// Đo lường hiệu suất
public class PerformanceTest
{
    public static void Main()
    {
        BinarySearchTree bst = new BinarySearchTree();
        Stopwatch stopwatch = new Stopwatch();

        stopwatch.Start();
        bst.Insert(50);
        bst.Insert(30);
        bst.Insert(20);
        bst.Insert(40);
        bst.Insert(70);
        bst.Insert(60);
        bst.Insert(80);
        stopwatch.Stop();
        Console.WriteLine("Thời gian chèn: " + stopwatch.ElapsedMilliseconds + " ms");

        stopwatch.Restart();
        Console.WriteLine("Tìm kiếm 40: " + bst.Search(40));
        stopwatch.Stop();
        Console.WriteLine("Thời gian tìm kiếm: " + stopwatch.ElapsedMilliseconds + " ms");

        stopwatch.Restart();
        bst.Delete(20);
        stopwatch.Stop();
        Console.WriteLine("Thời gian xóa: " + stopwatch.ElapsedMilliseconds + " ms");
    }
}
```

**Kiểm tra đơn vị**: Bạn có thể sử dụng NUnit để viết các bài kiểm tra đơn vị như sau:

```csharp
using NUnit.Framework;

[TestFixture]
public class BinarySearchTreeTests
{
    private BinarySearchTree bst;

    [SetUp]
    public void Setup()
    {
        bst = new BinarySearchTree();
    }

    [Test]
    public void TestInsertAndSearch()
    {
        bst.Insert(10);
        bst.Insert(5);
        bst.Insert(15);

        Assert.IsTrue(bst.Search(10));
        Assert.IsTrue(bst.Search(5));
        Assert.IsTrue(bst.Search(15));
        Assert.IsFalse(bst.Search(20));
    }

    [Test]
    public void TestDelete()
    {
        bst.Insert(10);
        bst.Insert(5);
        bst.Insert(15);
        bst.Delete(10);

        Assert.IsFalse(bst.Search(10));
        Assert.IsTrue(bst.Search(5));
        Assert.IsTrue(bst.Search(15));
    }
}
```

Đảm bảo rằng bạn đã cài đặt NUnit và cấu hình môi trường phát triển để chạy các bài kiểm tra đơn vị.
assistant