.NET Core 中的集合

作者:微信公众号:【架构师老卢】
3-14 18:38
87

📚 了解 .NET Core 中的集合

.NET Core 集合是 System.Collections 和 System.Collections.Generic 命名空间的一部分。.NET Core collections are part of the System.Collections and System.Collections.Generic namespaces.它们旨在保存和管理对象。集合类型的选择取决于数据操作(例如,搜索、插入、删除)以及集合在时间(执行这些操作的速度)和空间(集合使用的内存量)方面的性能特征。

1️⃣ List<T>: 动态数组

问题陈述:

您需要一个集合来按顺序存储元素并按索引访问它们,但元素的数量是预先未知的。

解决方案与示例:

List<T>是一个可以增长或收缩的动态数组。它提供基于索引的快速访问,但对于插入和删除操作可能会很慢,尤其是在开始时。

List<int> numbers = new List<int> { 1, 2, 3 };  
numbers.Add(4); // Adding an element  
int thirdElement = numbers[2]; // Accessing by index

时间复杂度:访问 — O(1),末尾插入/删除 — O(1),开头插入/删除 — O(n)。
空间复杂性:高效但动态增长,导致偶尔调整大小。

2️⃣ Dictionary<TKey、TValue>:键值对

问题陈述:

您需要通过唯一键存储和快速检索值。

解决方案与示例:

Dictionary<TKey, TValue>存储键值对。它使用密钥提供快速查找、添加和删除。

Dictionary<string, int> fruitBasket = new Dictionary<string, int>  
{  
    ["apple"] = 5,  
    ["banana"] = 2  
};  
fruitBasket["orange"] = 10; // Adding a key-value pair  
int appleCount = fruitBasket["apple"]; // Fast retrieval by key

时间复杂度:访问、插入、删除 — 平均 O(1)。
空间复杂度:由于存储键和值,因此高于列表。

3️⃣ HashSet<T>:唯一元素

问题陈述:

您需要一个集合来确保所有元素都是唯一的并执行快速查找。

解决方案与示例:

HashSet<T>存储唯一元素,并且非常有效地进行查找、添加和删除。

HashSet<int> uniqueNumbers = new HashSet<int> { 1, 2, 3 };  
bool added = uniqueNumbers.Add(4); // Returns true if successfully added  
bool containsThree = uniqueNumbers.Contains(3); // Fast lookup

时间复杂度:访问 — N/A,插入/删除/包含 — O(1) 平均。
空间复杂度:类似于 Dictionary,但仅存储唯一值。

高级方案和注意事项

  • 内存开销:考虑使用静态集合以节省内存。Array
  • 排序集合:使用和何时需要对元素进行排序。由于维持秩序,它们具有更高的时间复杂性。SortedSet<T>SortedDictionary<TKey, TValue>
  • 并发性:对于多线程应用程序,请考虑线程安全集合,例如 ,提供针对并发访问优化的性能。ConcurrentBag<T>ConcurrentDictionary<TKey, TValue>

实时用例:使用 Dictionary 的缓存系统<TKey、TValue>

场景:

实现简单的缓存机制,以使用唯一键存储和检索对象。

public class SimpleCache<T>  
{  
    private readonly Dictionary<string, T> _cache = new Dictionary<string, T>();  
  
    public T GetOrCreate(string key, Func<T> createItem)  
    {  
        if (!_cache.TryGetValue(key, out T cachedItem))  
        {  
            cachedItem = createItem();  
            _cache[key] = cachedItem;  
        }  
        return cachedItem;  
    }  
}

该缓存系统利用 O(1) 的平均时间复杂度进行检索和插入,使其成为需要快速访问存储数据的高性能应用程序的理想选择。Dictionary

🔄 迭代集合:性能见解

除了选择正确的集合类型之外,循环访问这些集合的方式也会显著影响性能。让我们深入了解迭代集合的细微差别以及优化此过程的一些高级技巧。

1️⃣ 遍历 List<T>

问题陈述:

您需要有效地处理每个元素。List<T>

解决方案与示例:

对于 ,由于直接索引访问,使用循环可提供最佳性能。List<T>for

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };  
for (int i = 0; i < numbers.Count; i++)  
{  
    // Process numbers[i]  
}

为什么?在 a 中按索引访问元素是 O(1)。循环避免了循环中使用的枚举器的开销。List<T>forforeach

2️⃣ 遍历字典<TKey、TValue>

问题陈述:

您需要有效地处理每个键值对。Dictionary<TKey, TValue>

解决方案与示例:

遍历一个 using 循环既高效又直接。Dictionary<TKey, TValue>foreach

Dictionary<string, int> fruitBasket = new Dictionary<string, int>  
{  
    ["apple"] = 5,  
    ["banana"] = 2,  
    ["orange"] = 10  
};  
foreach (var pair in fruitBasket)  
{  
    Console.WriteLine($"Fruit: {pair.Key}, Quantity: {pair. Value}");  
}

为什么?循环直接访问字典的键值对,而无需按键查找值,从而保持每次迭代的 O(1) 复杂度。foreach

3️⃣ HashSet<T> 迭代

问题陈述:

您需要处理 .HashSet<T>

解决方案与示例:

遍历 a 类似于 ;使用是有效的。HashSet<T>Dictionary<TKey, TValue>foreach

HashSet<int> uniqueNumbers = new HashSet<int> { 1, 2, 3, 4, 5 };  
foreach (int number in uniqueNumbers)  
{  
    // Process number  
}

为什么?循环有效地访问每个元素,利用哈希集的结构来保持性能。foreach

高级迭代模式

  • 并行处理:对于支持随机访问的集合(如 ),请考虑使用 PLINQ (Parallel LINQ) 进行可并行完成的数据处理,从而显著减少多核系统上的执行时间。List<T>Parallel.For
List<int> numbers = Enumerable.Range(1, 1000).ToList();  
Parallel.ForEach(numbers, number =>  
{  
    // Process number in parallel  
});
  • 使用 IEnumerable<T> 进行延迟迭代:在处理大型数据集或根据需要处理每个元素时,LINQ 查询提供“延迟”迭代,其中元素一次按需处理一个元素。对于大型集合,这可能更节省内存。IEnumerable<T>
IEnumerable<int> numbers = Enumerable.Range(1, 1000000);  
var evenNumbers = numbers.Where(n => n % 2 == 0);  
foreach (int number in evenNumbers)  
{  
    // Process even number  
}

实时用例:处理日志条目

场景:

系统处理存储在 中的日志条目,过滤错误并对每个条目执行操作。List<LogEntry>

public class LogEntry  
{  
    public DateTime Timestamp { get; set; }  
    public string Message { get; set; }  
    public LogLevel Level { get; set; }  
}  
  
List<LogEntry> logEntries = GetLogEntries();  
var errorEntries = logEntries.Where(entry => entry.Level == LogLevel.Error);  
  
foreach (var entry in errorEntries)  
{  
    AlertSystem(entry); // Process error entry  
}

此示例演示如何使用 LINQ 进行筛选,然后使用循环进行处理,演示延迟迭代和对集合的筛选子集的高效枚举的组合。foreach

🚀 优化收款操作:高级策略

除了选择正确的集合和高效迭代之外,优化集合中的搜索、插入、删除和更新等操作可以显著提高性能,尤其是在复杂和数据密集型应用程序中。让我们探讨用于在 .NET Core 集合中优化这些操作的高级策略。

集合中的搜索优化

问题陈述:

您经常在集合中搜索元素,从而影响性能。

解决方案与示例:排序集合中的二进制搜索

对于元素排序的集合,二进制搜索 () 提供对数搜索时间,这比线性搜索时间有了显着改进。List<T>List<T>.BinarySearch

List<int> sortedNumbers = new List<int> { 1, 3, 5, 7, 9 };  
int index = sortedNumbers.BinarySearch(5); // Logarithmic search time  
if (index >= 0) // Found  
{  
    // Process found item  
}

为什么?二进制搜索每次都会将搜索间隔分成两半,从而使排序集合中的搜索效率极高。

插入和删除优化

问题陈述:

在大型集合中间插入和删除速度很慢。

示例解决方案:用于频繁插入和删除的 LinkedList<T>

当应用程序频繁插入和删除元素时,尤其是在集合的中间,可能比LinkedList<T>List<T>

LinkedList<int> linkedList = new LinkedList<int>();  
var firstNode = linkedList.AddFirst(1); // Constant time  
linkedList.AddAfter(firstNode, 2); // Efficient insert  
linkedList.Remove(firstNode); // Efficient delete

为什么? 允许恒定时间插入和删除,因为它只需要更新下一个和上一个引用,而无需移动元素。LinkedList<T>

键值集合中的更新优化

问题陈述:

您需要在键值集合中进行有效的更新。

解决方案与示例:用于快速更新Dictionary<TKey, TValue>

Dictionary<TKey, TValue>按键提供快速更新,非常适合频繁更新值的方案。

Dictionary<string, string> settings = new Dictionary<string, string>  
{  
    ["theme"] = "dark",  
    ["fontSize"] = "medium"  
};  
settings["theme"] = "light"; // Fast update by key

为什么?字典的哈希表实现可确保在近乎恒定的时间内执行更新,这比在列表中搜索和更新要快得多。

内存和性能注意事项

  • 内存使用情况:在优化时间复杂度的同时,还要考虑集合的内存占用情况。例如,对于某些操作来说速度更快,但由于其内部哈希表结构,使用更多的内存。Dictionary<TKey, TValue>HashSet<T>List<T>
  • 对象池:对于具有高分配率和解除分配率的应用程序,请考虑使用对象池来重用对象,而不是频繁地创建和销毁它们。这可以显著减少垃圾回收开销并提高性能。

实时用例:高性能日志记录系统

场景:

高性能日志记录系统需要高效地插入、搜索和删除日志消息。

ConcurrentDictionary<DateTime, string> logs = new ConcurrentDictionary<DateTime, string>();  
  
public void AddLog(DateTime timestamp, string message)  
{  
    logs[timestamp] = message; // Fast insertion  
}  
  
public string GetLog(DateTime timestamp)  
{  
    logs.TryGetValue(timestamp, out string message); // Fast search  
    return message;  
}  
  
public void DeleteLog(DateTime timestamp)  
{  
    logs.TryRemove(timestamp, out _); // Fast deletion  
}

此示例演示了如何使用 来确保线程安全、快速的插入、搜索和删除,这对于效率和并发性至关重要的高性能日志记录系统至关重要。ConcurrentDictionary<TKey, TValue>

🛠 集合的高级内存管理技术

在高性能 .NET Core 应用程序中,管理集合的内存使用情况与优化其操作一样重要。高效的内存管理可以降低 GC(垃圾回收器)压力、减少延迟并提高吞吐量。让我们深入研究专门为 .NET Core 应用程序中的集合量身定制的高级内存管理技术。

了解集合和内存使用情况

.NET Core 中的集合(如 、 和 )会动态调整大小以容纳更多元素。这种调整大小操作在性能和内存使用方面可能会付出高昂的代价,尤其是对于大型集合。List<T>Dictionary<TKey, TValue>HashSet<T>

预调整集合大小

问题陈述:

由于动态添加而频繁调整集合的大小会导致性能开销和内存使用量增加。

示例解决方案:使用容量进行初始化

如果预先知道元素的大致数量,则使用特定容量初始化集合可以显著减少调整大小操作。

// Knowing we'll have approximately 1000 elements  
List<int> numbers = new List<int>(1000);

此方法对 和 特别有效,其中指定初始容量可以避免多次调整大小操作,从而减少内存分配和 GC 开销。List<T>Dictionary<TKey, TValue>

使用 ArrayPool 和 MemoryPool

先进技术:

对于需要大型阵列或缓冲区的方案,使用 or 直接管理内存可以显著提高性能。ArrayPool<T>MemoryPool<T>

using System.Buffers;  
  
// Renting an array from the pool  
int[] pooledArray = ArrayPool<int>.Shared.Rent(1000);  
  
try  
{  
    // Use the array  
}  
finally  
{  
    // Returning the array to the pool  
    ArrayPool<int>.Shared.Return(pooledArray);  
}

此技术对于密集型处理任务中使用的临时缓冲区或数组特别有用。它通过重用阵列而不是创建和丢弃它们来降低 GC 压力。

用于提高内存效率的稀疏集合

问题陈述:

在传统集合中存储稀疏数据会导致未占用元素不必要的内存使用。

解决方案与示例:自定义稀疏集合

对于稀疏数据,实现有效表示稀疏数据的自定义集合可以显著减少内存使用量。

public class SparseArray<T>  
{  
    private readonly Dictionary<int, T> _data = new Dictionary<int, T>();  
    private readonly T _defaultValue;  
  
    public SparseArray(T defaultValue = default)  
    {  
        _defaultValue = defaultValue;  
    }  
  
    public T this[int index]  
    {  
        get => _data.TryGetValue(index, out T value) ? value : _defaultValue;  
        set => _data[index] = value;  
    }  
}

这使用字典仅存储已显式设置的元素,这使得它对于稀疏数据的内存效率比填充了未占用索引的默认值的常规数组或列表要高得多。SparseArray<T>

节省内存的数据结构

先进技术:

利用专用数据结构(如布尔数据)或使用命名空间中的数据结构可以为特定数据类型提供更节省内存的存储。BitArraySystem.Collections.Specialized

BitArray flags = new BitArray(1000);

A 对于存储大量布尔值特别节省内存,每个布尔值只使用一个位而不是整个字节或更多字节。BitArray

实时用例:高效的网络数据包处理

场景:

应用程序处理网络数据包,需要临时缓冲区来操作数据包数据。

using System.Buffers;  
  
public void ProcessPacket(byte[] packet)  
{  
    byte[] buffer = ArrayPool<byte>.Shared.Rent(packet.Length);  
  
    try  
    {  
        // Copy packet data to buffer and process  
    }  
    finally  
    {  
        ArrayPool<byte>.Shared.Return(buffer);  
    }  
}

此用例演示了在高吞吐量、低延迟网络应用中管理临时缓冲区的有效性,从而最大限度地减少了 GC 压力并增强了性能。ArrayPool<T>

🌟 利用集合的并行处理

在当今的多核处理器环境中,并行处理可以显著提高处理大量数据的应用程序的性能。.NET Core 提供对并行性的可靠支持,使开发人员能够利用多线程和异步处理来加快对集合的操作。本节深入探讨了对集合进行并行处理、确保有效利用系统资源和最大程度地减少瓶颈的高级策略。

并行 LINQ (PLINQ)

问题陈述:

按顺序处理大型数据集可能会导致系统资源利用率欠佳,从而导致执行时间延长。

解决方案与示例:利用 PLINQ 进行数据处理

并行 LINQ (PLINQ) 是 LINQ 的扩展,它支持并行执行查询。它可以自动将数据处理分布在多个线程之间,使其成为可以独立对集合元素执行的操作的理想选择。

var numbers = Enumerable.Range(1, 10000);  
var evenNumbers = numbers.AsParallel().Where(n => n % 2 == 0).ToList();

此示例演示了如何使用 PLINQ 通过利用多个内核有效地过滤大型集合中的偶数。

任务并行库 (TPL)

先进技术:

任务并行库 (TPL) 为并行编程提供了更高级别的抽象,从而简化了对集合执行并行操作的过程。

解决方案与示例:使用 TPL 并行 ForEach

var items = Enumerable.Range(1, 10000).ToList();  
Parallel.ForEach(items, item =>  
{  
    // Process item  
});

此代码片段演示如何使用并行处理集合中的每个项。TPL 管理数据的分区和线程的调度,使编写并行代码变得更加容易。Parallel.ForEach

并发集合

问题陈述:

在多线程环境中管理数据完整性和线程安全性可能具有挑战性。

解决方案及示例:使用并发集合

.NET 提供了多个线程安全集合,例如 、 、 和 ,专为并发访问而设计,无需手动同步。

ConcurrentDictionary<int, string> concurrentDictionary = new ConcurrentDictionary<int, string>();  
  
Parallel.For(0, 10000, i =>  
{  
    concurrentDictionary.TryAdd(i, $"Value {i}");  
});

此示例使用 a 并行添加键值对,确保线程安全和数据完整性,而无需显式锁定。

用于负载平衡的自定义分区

先进技术:

自定义分区可用于在线程之间更均匀地分配工作负载,尤其是在处理处理时间不同的项目时。

var rangePartitioner = Partitioner.Create(0, items.Count, 1000); // Partition into ranges of 1000  
Parallel.ForEach(rangePartitioner, (range, loopState) =>  
{  
    for (int i = range.Item1; i < range.Item2; i++)  
    {  
        // Process items\[i\]  
    }  
});

自定义分区允许对工作分配进行更精细的控制,从而有助于实现更高效的负载平衡。

实时用例:图像处理

场景:

应用程序需要将筛选器应用于集合中存储的大量图像。

List<Image> images = LoadImages();  
Parallel.ForEach(images, image =>  
{  
    ApplyFilter(image);  
});

🌟 利用集合的并行处理

在当今的多核处理器环境中,并行处理可以显著提高处理大量数据的应用程序的性能。.NET Core 提供对并行性的可靠支持,使开发人员能够利用多线程和异步处理来加快对集合的操作。本节深入探讨了对集合进行并行处理、确保有效利用系统资源和最大程度地减少瓶颈的高级策略。

并行 LINQ (PLINQ)

问题陈述:

按顺序处理大型数据集可能会导致系统资源利用率欠佳,从而导致执行时间延长。

解决方案与示例:利用 PLINQ 进行数据处理

并行 LINQ (PLINQ) 是 LINQ 的扩展,它支持并行执行查询。它可以自动将数据处理分布在多个线程之间,使其成为可以独立对集合元素执行的操作的理想选择。

var numbers = Enumerable.Range(1, 10000);  
var evenNumbers = numbers.AsParallel().Where(n => n % 2 == 0).ToList();

此示例演示了如何使用 PLINQ 通过利用多个内核有效地过滤大型集合中的偶数。

任务并行库 (TPL)

先进技术:

任务并行库 (TPL) 为并行编程提供了更高级别的抽象,从而简化了对集合执行并行操作的过程。

解决方案与示例:使用 TPL 并行 ForEach

var items = Enumerable.Range(1, 10000).ToList();  
Parallel.ForEach(items, item =>  
{  
    // Process item  
});

此代码片段演示如何使用并行处理集合中的每个项。TPL 管理数据的分区和线程的调度,使编写并行代码变得更加容易。Parallel.ForEach

并发集合

问题陈述:

在多线程环境中管理数据完整性和线程安全性可能具有挑战性。

解决方案及示例:使用并发集合

.NET 提供了多个线程安全集合,例如 、 、 和 ,专为并发访问而设计,无需手动同步。

ConcurrentDictionary<int, string> concurrentDictionary = new ConcurrentDictionary<int, string>();  
  
Parallel.For(0, 10000, i =>  
{  
    concurrentDictionary.TryAdd(i, $"Value {i}");  
});

此示例使用 a 并行添加键值对,确保线程安全和数据完整性,而无需显式锁定。

用于负载平衡的自定义分区

先进技术:

自定义分区可用于在线程之间更均匀地分配工作负载,尤其是在处理处理时间不同的项目时。

var rangePartitioner = Partitioner.Create(0, items.Count, 1000); // Partition into ranges of 1000  
Parallel.ForEach(rangePartitioner, (range, loopState) =>  
{  
    for (int i = range.Item1; i < range.Item2; i++)  
    {  
        // Process items[i]  
    }  
});

自定义分区允许对工作分配进行更精细的控制,从而有助于实现更高效的负载平衡。

实时用例:图像处理

场景:

应用程序需要将筛选器应用于集合中存储的大量图像。

List<Image> images = LoadImages();  
Parallel.ForEach(images, image =>  
{  
    ApplyFilter(image);  
});

此用例展示了并行处理在图像处理等密集型任务中的强大功能,其中对单个项目(图像)的操作是独立的,可以并发执行,从而大大缩短了总体处理时间。

📦 集合的序列化和反序列化

序列化将数据结构或对象状态转换为可以存储或传输并在以后重新构造的格式(如 JSON、XML 或二进制文件)。反序列化是相反的过程。高效的序列化和反序列化对于涉及数据持久性、网络或进程间通信的应用程序至关重要。

使用 System.Text.Json 进行 JSON 序列化

问题陈述:

需要将集合序列化为 JSON,以便 Web API 响应或以基于文本的格式存储。

解决方案与示例:将集合序列化为 JSON

.NET Core 的命名空间为 JSON 序列化和反序列化提供高性能、低分配和符合标准的功能。它是在 .NET Core 应用程序中处理 JSON 数据的理想选择。System.Text.Json

using System.Text.Json;  
  
var products = new List<Product>  
{  
    new Product { Id = 1, Name = "Laptop", Price = 1200.50M },  
    new Product { Id = 2, Name = "Smartphone", Price = 800.99M }  
};  
  
string json = JsonSerializer.Serialize(products);

此代码片段演示了如何使用 将产品列表序列化为 JSON 字符串。System.Text.Json

提高性能的二进制序列化

先进技术:

与基于文本的序列化相比,二进制序列化提供了更紧凑的格式和更快的处理速度,使其适用于高性能应用程序,包括需要临时存储或进程间通信的应用程序。

解决方案与示例:使用 System.Runtime.Serialization.Formatters.Binary

using System.Runtime.Serialization.Formatters.Binary;  
using System.IO;  
  
var numbers = new List<int> { 1, 2, 3, 4, 5 };  
  
using (var ms = new MemoryStream())  
{  
    var formatter = new BinaryFormatter();  
    formatter.Serialize(ms, numbers);  
    byte[] bytes = ms.ToArray();  
    // bytes can now be stored or transmitted  
}

此示例用于将整数列表序列化为二进制格式。但请注意,出于安全考虑,不建议将其用于新开发。应考虑基于文本的序列化或自定义二进制序列化技术等替代方法。BinaryFormatterBinaryFormatterSystem.Text.Json

针对复杂方案的自定义序列化

问题陈述:

标准序列化机制可能不足以满足复杂的对象图或需要特定序列化格式的情况。

解决方案与示例:实现自定义序列化逻辑

对于复杂的方案或需要精确控制序列化过程时,实现自定义序列化逻辑可以提供所需的灵活性。

public class Product  
{  
    public int Id { get; set; }  
    public string Name { get; set; }  
    public decimal Price { get; set; }  
  
    // Custom serialization logic  
    public string Serialize()  
    {  
        return $"{Id},{Name},{Price}";  
    }  
  
    // Custom deserialization logic  
    public static Product Deserialize(string data)  
    {  
        var parts = data.Split(',');  
        return new Product  
        {  
            Id = int.Parse(parts[0]),  
            Name = parts[1],  
            Price = decimal.Parse(parts[2])  
        };  
    }  
}

此方法允许完全控制序列化和反序列化过程,从而实现标准序列化程序无法提供的优化和自定义。

实时用例:配置管理

场景:

应用程序需要保留和检索其配置设置,这些设置表示为键值对的集合。

var settings = new Dictionary<string, string>  
{  
    { "theme", "dark" },  
    { "language", "en-US" }  
};  
  
string jsonSettings = JsonSerializer.Serialize(settings);  
File.WriteAllText("settings.json", jsonSettings);  
  
// Later...  
string loadedJson = File.ReadAllText("settings.json");  
var loadedSettings = JsonSerializer.Deserialize<Dictionary<string, string>>(loadedJson);

此用例演示了字典到 JSON 的序列化和反序列化,从而实现了配置设置的高效存储和检索

🛡️ 收集操作中的错误处理

集合操作中的错误处理对于正常管理意外情况至关重要,例如尝试越界访问元素、在迭代时修改集合或遇到空引用。

尝试安全访问的方法

.NET 中的许多集合都提供方法(如字典),这些方法安全地尝试操作并返回指示成功的布尔值,从而避免不存在的键出现异常。TryTryGetValue

Dictionary<string, int> fruitCounts = new Dictionary<string, int>  
{  
    {"apple", 10},  
    {"banana", 5}  
};  
  
if (fruitCounts.TryGetValue("orange", out int count))  
{  
    Console.WriteLine($"Oranges: {count}");  
}  
else  
{  
    Console.WriteLine("Oranges not found");  
}

在枚举期间处理修改

在枚举集合时修改集合可能会导致 .使用策略,例如将项复制到新集合或使用专为此类方案设计的并发集合。InvalidOperationException

var numbers = new List<int> { 1, 2, 3, 4, 5 };  
var numbersToRemove = new List<int>();  
  
foreach (var number in numbers)  
{  
    if (number % 2 == 0) // Condition to remove item  
    {  
        numbersToRemove.Add(number);  
    }  
}  
  
foreach (var number in numbersToRemove)  
{  
    numbers. Remove(number);  
}

🔍 集合中的数据验证

在将数据添加到集合之前对其进行验证有助于维护数据结构和应用程序的完整性。在处理用户输入或来自外部来源的数据时,这一点尤为重要。

自定义验证逻辑

为复杂方案或与现有验证框架集成时实现自定义验证逻辑。这可以在插入时完成,也可以作为单独验证步骤的一部分完成。

public class Product  
{  
    public int Id { get; set; }  
    public string Name { get; set; }  
    public decimal Price { get; set; }  
  
    public static bool Validate(Product product)  
    {  
        return product.Price > 0; // Simple validation logic  
    }  
}  
  
var products = new List<Product>();  
var newProduct = new Product { Id = 1, Name = "Laptop", Price = -1000 };  
  
if (Product.Validate(newProduct))  
{  
    products.Add(newProduct);  
}  
else  
{  
    Console.WriteLine("Invalid product");  
}

异常处理策略

适当的异常处理策略使应用程序能够通过重试操作、记录错误或提供用户反馈来优雅地响应错误。

Try-Catch 块

使用块包围有风险的操作,以捕获异常并适当地处理它们,无论是通过日志记录、提醒用户还是执行纠正措施。try-catch

try  
{  
    var index = 10;  
    var item = numbers[index]; // This might throw ArgumentOutOfRangeException  
}  
catch (ArgumentOutOfRangeException ex)  
{  
    Console.WriteLine($"Error accessing index: {ex.Message}");  
}

并行操作的 AggregateException

使用并行处理或任务时,处理处理在并发操作期间可能引发的多个异常。AggregateException

try  
{  
    Parallel.ForEach(numbers, number =>  
    {  
        // Operation that might throw an exception  
    });  
}  
catch (AggregateException ex)  
{  
    foreach (var innerEx in ex.InnerExceptions)  
    {  
        Console.WriteLine(innerEx.Message);  
    }  
}

实时用例:电子商务应用程序结账流程

在电子商务应用程序中,在结账过程中,验证购物车中的商品、计算总数并安全高效地处理付款、处理发生的任何错误以防止结账失败并确保流畅的用户体验至关重要。

try  
{  
    ValidateCartItems(cartItems); // Validates each item in the cart  
    var total = CalculateTotal(cartItems); // Calculates total price  
    ProcessPayment(total); // Attempts to process payment  
}  
catch (PaymentProcessingException ex)  
{  
    // Handle payment processing errors  
    LogError(ex);  
    InformUser("Payment processing failed. Please try again.");  
}  
catch (Exception ex)  
{  
    // General error handling  
    LogError(ex);  
    InformUser("An error occurred during checkout. Please contact support.");  
}
相关留言评论
昵称:
邮箱:
阅读排行