嘿! 今天,我有一些特别的东西要与大家分享 - 60 个 C# 代码片段的汇编,我发现它们对我自己的工作非常有帮助。
在本文中,我们不仅要了解这些片段如何解决日常编程问题,还要了解它们为何如此工作。 这是为了建立更深入的理解,而不仅仅是快速复制粘贴工作。
如果您一直在使用 C# 并且曾经发现自己陷入问题,不确定如何有效地解决它,那么这些片段适合您。 如果您对 C# 比较陌生并且正在尝试了解如何更有效地使用该语言,那么它们也适合您。
好了,说够了。 让我们一起开始探索这些代码片段。 我希望你发现它们和我一样有用。
在我们继续之前,在提供的示例中,我尝试添加一点幽默感并列出一些用例。 希望这也能让你开心,因为至少我总是更容易记住有趣的事情:)让我们开始吧!
public int BinarySearch(int[] arr, int target)
{
int left = 0;
int right = arr.Length - 1;
while (left <= right)
{
int mid = left + (right - left) / 2;
if (arr[mid] == target)
return mid;
if (arr[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return -1;
}
将此代码视为搜索方法中的福尔摩斯。 您知道,与其浪费时间到处寻找特定的物品,不如直接切入正题不是很好吗? 这正是二分查找的作用——它通过划分和征服来节省你的时间(和理智)!
用例:
在已排序的用户列表中搜索特定用户
在已排序的图书馆数据库中查找特定的书籍
public void BubbleSort(int[] arr)
{
int len = arr.Length;
for (int i = 0; i < len - 1; i++)
for (int j = 0; j < len - i - 1; j++)
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
就像你有时把所有衣服扔到空中然后排列它们一样(来吧,我们都会这样做,对吧?),冒泡排序会随机排列数组中的数字,直到它们处于完美的顺序。 虽然这不是最快的排序,但它绝对是一个有趣的观看方式。
用例:
按升序对排行榜分数进行排序
按价格组织产品列表
public void DFS(int v, bool[] visited, List<int>[] adj)
{
visited[v] = true;
Console.Write(v + " ");
foreach (int neighbour in adj[v])
{
if (!visited[neighbour])
DFS(neighbour, visited, adj);
}
}
DFS就像那个朋友,当你们一起去徒步旅行时,只需探索每一个角落。 在考虑尝试一条新道路之前,它会尽可能深入地探索一条道路。 当您需要对图表的所有节点进行彻底、全面的搜索时,请使用它。
用例:
在迷宫中寻找路径
分析网络连接
public void PrintFibonacci(int n)
{
int a = 0, b = 1, c;
for(int i = 0; i < n; i++)
{
Console.Write(a + " ");
c = a + b;
a = b;
b = c;
}
}
想要享受一些优雅的数字吗? 斐波那契数列就像数字的交响曲,每个数字都是前两个数字的和谐融合。 此代码片段可帮助您生成由“n”项组成的斐波那契数列。
用例:
解决数学中与递归序列相关的问题
在与搜索和排序甚至密码学相关的算法中
public int Factorial(int n)
{
if (n == 0)
return 1;
else
return n * Factorial(n - 1);
}
还记得你以为自己可以吃无数块饼干,然后意识到自己可能吃不完 10 块吗? 嗯,阶乘有点像这样——它们涉及将所有正整数乘以某个数字,并且它们很快就会变大! 当您需要计算阶乘时,请使用此代码片段。
用例:
在计算统计组合和排列时
用于某些搜索和查询优化算法
public int[,] MultiplyMatrix(int[,] a, int[,] b)
{
int[,] result = new int[a.GetLength(0),b.GetLength(1)];
for (int i = 0; i < result.GetLength(0); i++)
{
for (int j = 0; j < result.GetLength(1); j++)
{
result[i, j] = 0;
for (int k = 0; k < a.GetLength(1); k++) // or k<b.GetLength(0)
result[i, j] += a[i, k] * b[k, j];
}
}
return result;
}
矩阵乘法就像一个聚会,其中第一个矩阵的每一行都与第二个矩阵的每一列混合在一起。 结果呢? 一个全新的矩阵,其元素是根据乘法对的总和创建的。 因此,当您希望矩阵举办派对时,此片段将成为您的 DJ!
用例:
在计算机图形学中将 3D 对象转换为不同的比例或位置
用数值方法求解线性方程组
public bool IsPalindrome(string str)
{
str = str.ToLower();
int i = 0, j = str.Length - 1;
while (i < j)
{
if (str[i++] != str[j--])
return false;
}
return true;
}
如果您不确定某个单词或短语是否是秘密回文,此功能可以为您提供支持。
用例:
检查单词是否为文字游戏或拼图的回文
生物信息学中验证 DNA 序列的对称性
public List<int> SieveOfEratosthenes(int n)
{
bool[] prime = new bool[n + 1];
for (int i = 0; i <= n; i++)
prime[i] = true;
for (int p = 2; p * p <= n; p++)
{
if (prime[p] == true)
{
for (int i = p * p; i <= n; i += p)
{
prime[i] = false;
}
}
}
List<int> primeNumbers = new List<int>();
for (int i = 2; i <= n; i++)
{
if (prime[i])
{
primeNumbers.Add(i);
}
}
return primeNumbers;
}
埃拉托斯特尼筛法是一种古老(但却是黄金)的算法,用于找出给定数字“n”之前的所有素数。 这就像一个筛子筛掉合数,只留下素数。
用例:
为加密应用程序生成素数
在数论和数学问题中的应用
public void QuickSort(int[] arr, int low, int high)
{
if (low < high)
{
int pi = Partition(arr, low, high);
QuickSort(arr, low, pi - 1);
QuickSort(arr, pi + 1, high);
}
}
int Partition(int[] arr, int low, int high)
{
int pivot = arr[high];
int i = (low - 1);
for (int j = low; j <= high - 1; j++)
{
if (arr[j] < pivot)
{
i++;
Swap(arr, i, j);
}
}
Swap(arr, i + 1, high);
return (i + 1);
}
void Swap(int[] arr, int a, int b)
{
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
QuickSort,顾名思义,是一种快速高效的排序算法。 它选择一个主元元素,然后围绕该主元对数组进行分区。
用例:
在时间复杂度很重要的软件应用程序中对数据进行排序
在选择算法中,选择是根据某些条件完成的
public int GetLength(ListNode head)
{
int count = 0;
ListNode current = head;
while (current != null)
{
count++;
current = current.next;
}
return count;
}
这个函数会遍历链表,就像你来回踱步一样,不耐烦地等待你的咖啡因修复,并计算节点的数量。
用例:
确定动态构建的数据结构的大小
评估链表的长度以解决各种数据操作问题
string[] fruits = { "Apple", "banana", "cherry" };
var fruitsDictionary = fruits.Select((fruit, index) => new { fruit, index })
.ToDictionary(x => x.fruit, x => x.index);
我们都注重效率,Linq 是一个很棒的工具,可以帮助我们在单个语句中填充字典。 在此代码片段中,我将获取一个水果数组并将其转换为字典,使用水果名称作为键,使用索引作为值。
用例:
快速将对象列表转换为查找表
将数组转换为字典以便于访问
Dictionary<string, Dictionary<string, int>> nestedDictionary =
new Dictionary<string, Dictionary<string, int>>();
nestedDictionary["Fruits"] = new Dictionary<string, int> { { "Apple", 1 }, { "Banana", 2 } };
嵌套字典就像数据结构的初始:字典中的字典。 当您需要存储复杂的数据并且需要维护不同实体之间的关系时,这些功能非常有用。
用例:
存储实体之间的复杂关系
表示产品列表中的多级类别
ConcurrentDictionary<string, int> concurrentDictionary = new ConcurrentDictionary<string, int>();
concurrentDictionary.TryAdd("Apple", 1);
concurrentDictionary.TryUpdate("Apple", 2, 1);
当您需要同时添加或更新条目时,它可确保线程安全操作。 这就像在繁忙的十字路口有一个交通管制员。
用例:
实现涉及字典的多线程操作
并行计算场景下更新共享资源
Dictionary<string, int> fruits = new Dictionary<string, int> { { "Apple", 1 }, { "Banana", 2 }, { "Cherry", 3 } };
var sortedDictionary = fruits.OrderBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value);
有时,按键对字典进行排序可能是一个方便的功能,特别是当您想要按特定顺序显示条目时。 使用 Linq,您可以轻松实现这一点,使您的字典成为一个有序的集合。
用例:
对字典条目进行排序以供显示
为需要排序输入的算法准备数据
public class SimpleCache<TKey, TValue>
{
private Dictionary<TKey, TValue> cache = new Dictionary<TKey, TValue>();
public TValue Get(TKey key, Func<TKey, TValue> valueFactory)
{
if (!cache.TryGetValue(key, out TValue value))
{
value = valueFactory(key);
cache[key] = value;
}
return value;
}
}
我觉得这特别酷。 使用字典,您可以构建一个简单的缓存,以避免昂贵的计算或网络调用。 您可以使用密钥和工厂函数调用 Get。 如果键不在字典中,它将使用该函数创建值,将其添加到字典中,然后返回它。
用例:
避免计算算法中的重复计算
缓存来自数据库或 API 的常用数据
Dictionary<string, int> fruits = new Dictionary<string, int> { { "Apple", 1 }, { "Banana", 2 } };
Dictionary<string, int>.ValueCollection fruitValues = fruits.Values;
许多人忘记了可以使用 Values 属性将字典值作为集合直接访问。 当您只需要使用字典中的值而不是键时,这会很方便。
用例:
总结字典中的所有值
查找字典中的最小值或最大值
7. 使用 AsParallel 进行并行操作
Dictionary<string, int> largeDictionary = ... // Large dictionary
var modifiedDictionary = largeDictionary.AsParallel().Select(kvp => new { kvp.Key, Value = kvp.Value * 2 }).ToDictionary(x => x.Key, x => x.Value);
LINQ 中的 AsParallel 方法提供了一种并行执行操作的方法,这可以在处理大型字典时显着提高性能。 请注意,您应该谨慎使用它,因为它可能不会为较小的字典带来好处,甚至可能由于并行性的开销而降低性能。
用例:
对大型字典执行耗时的操作
对字典中的每个值应用函数进行数据转换
8.UsingDictionary<TKey, TValue>.KeyCollection
Dictionary<string, int> fruits = new Dictionary<string, int> { { "Apple", 1 }, { "Banana", 2 } };
Dictionary<string, int>.KeyCollection fruitKeys = fruits.Keys;
与我们之前讨论的 ValueCollection 类似,KeyCollection 使您可以直接访问字典中的键。 这是迭代键而不用担心值的好方法。
用例:
检查字典中是否存在某个键
迭代所有键以进行数据分析
9. 使用HashSet<T>删除重复项
Dictionary<string, int> fruitsWithDuplicates = new Dictionary<string, int> { { "Apple", 1 }, { "Apple", 1 }, { "Banana", 2 } };
Dictionary<string, int> fruitsWithoutDuplicates = new HashSet<string>(fruitsWithDuplicates.Keys).ToDictionary(x => x, x => fruitsWithDuplicates[x]);
HashSet<T> 是一个经常被忽视但功能强大的工具,用于从集合中删除重复项。 当与字典结合使用时,它可以用于删除重复的键并创建新的字典。
用例:
从用户输入字典中删除重复项
预处理期间清理数据
SortedDictionary<string, int> sortedFruits = new SortedDictionary<string, int> { { "Apple", 1 }, { "Banana", 2 } };
SortedDictionary<TKey, TValue> 自动对字典中的键进行排序。 当您不断需要数据处于排序状态时,它会很有用。 但请注意,排序过程可能会带来性能成本。
用例:
实现优先级队列
维护二分搜索操作的排序数据
Task.Run(() =>
{
// Long running operation...
});
Task.Run 是启动后台任务的便捷快捷方式。 这相当于创建一个新任务然后调用 Start(),但代码更少。 谁不喜欢简洁?
用例:
开始一项不需要立即关注的新操作
在不阻塞主线程的情况下进行繁重的计算
CancellationTokenSource cts = new CancellationTokenSource();
Task.Run(() =>
{
// Check the cancellation token regularly
while (!cts.Token.IsCancellationRequested)
{
// Do some work...
}
}, cts.Token);
// Cancel the task
cts.Cancel();
取消令牌可让您优雅地停止正在执行的任务。 这就像友好地拍一下你的肩膀,告诉你的任务是时候停止了。
用例:
退出应用程序时停止后台操作
当不再需要时取消长时间运行的操作
int counter = 0;
Parallel.For(0, 10000, i => Interlocked.Increment(ref counter));
Interlocked 类为多个线程共享的变量提供原子操作。 Interlocked.Increment 是一种在多线程环境中安全递增计数器的方法。 它确保您的计数不会错过任何一个节拍。
用例:
多线程场景下更新共享计数器
确保基于线程的竞争条件不会导致错误的结果
Mutex mutex = new Mutex();
mutex.WAItOne();
try
{
// Do some work...
}
finally
{
mutex.ReleaseMutex();
}
互斥体就像线程的红绿灯。 它们确保一次只有一个线程可以访问一段代码,从而防止出现令人不快的意外情况。
用例:
保护代码的关键部分免遭同时访问
跨多个线程同步操作
BlockingCollection<int> data = new BlockingCollection<int>();
Task.Run(() =>
{
while (!data.IsCompleted)
{
int item;
if (data.TryTake(out item))
{
// Process item...
}
}
});
BlockingCollection<T> 提供了一种线程安全的方式来跨多个线程处理数据。 这就像为您的共享数据提供一个安全的保管库。
用例:
实施生产者-消费者场景
在多个线程之间安全地交换数据
Task<int> t = Task.Run(() => 42);
t.ContinueWith((antecedent) => Console.WriteLine(antecedent.Result));
任务延续允许您指定任务完成后应该发生的情况。 这就像设置一排多米诺骨牌,其中一个会触发下一个。
用例:
任务完成时执行操作
创建依赖任务链
Task task = Task.Run(() => { throw new Exception("Oops!"); });
try
{
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine(ex.InnerExceptions[0].Message); // Prints "Oops!"
}
如果任务中的异常处理不正确,可能会导致整个应用程序崩溃。 通过这个技巧,您可以优雅地处理任务中的异常,就像处理一杯香槟一样。
用例:
捕获并处理任务中抛出的异常
使您的应用程序能够适应后台任务中的错误
ThreadLocal<int> threadLocal = new ThreadLocal<int>(() => 42);
Console.WriteLine(threadLocal.Value); // Prints 42
ThreadLocal<T> 允许您定义每个线程唯一的数据。 这就像为每个线程提供了自己的私有存储柜。
用例:
实现线程特定的数据以优化性能
存储不应跨线程共享的状态
SemaphoreSlim semaphore = new SemaphoreSlim(2); // Limit to 2 threads
Task.Run(() =>
{
semaphore.Wait();
try
{
// Do some work...
}
finally
{
semaphore.Release();
}
});
信号量非常适合控制对容量有限的资源的访问。 它就像夜总会的保镖,控制可以进入的线程数量。
用例:
限制可以访问资源的线程数量
通过限制并发防止资源耗尽
ManualResetEvent mre = new ManualResetEvent(false);
Task.Run(() =>
{
// Wait for the event to be set
mre.WaitOne();
// Do some work...
});
// Set the event
mre.Set();
手动重置事件是跨多个线程同步操作的绝佳工具。 它就像比赛中的发令枪,向所有线程发出开始运行的信号。
用例:
同步多个线程的启动时间
等待另一个线程满足某个条件
List<string> myList = new List<string> {"A", "B", "C"};
ReadOnlyCollection<string> myReadOnlyList = myList.AsReadOnly();
您可以使用 AsReadOnly 方法创建只读集合。 这可以确保集合不会被意外修改,这在处理重要数据时至关重要。 就像博物馆里的无价之宝一样,它只能看,但不能触摸!
用例:
当您想要共享集合但不希望它被修改时
防止代码中出现不必要的副作用
var array = new[] { "A", "B", "C" };
您可以使用 new[] 关键字创建隐式类型数组。 这可以节省输入并保持代码干净简单。 这就像数组创建的洗碗机!
用例:
当你想创建一个内联数组时
当数组的类型从上下文中显而易见时
Queue<int> queue = new Queue<int>();
queue.Enqueue(1);
queue.Enqueue(2);
int first = queue.Dequeue();
Stack<int> stack = new Stack<int>();
stack.Push(1);
stack.Push(2);
int last = stack.Pop();
Queue 和 Stack 类提供了处理有序集合的有效方法。 队列遵循“先进先出”(FIFO) 策略,堆栈遵循“后进先出”(LIFO) 策略。 这些非常适合模拟现实世界的情况,例如售票亭的队列或一堆盘子。
用例:
当您需要实施 FIFO 或 LIFO 策略时
模拟现实世界的情况
HashSet<string> hashSet = new HashSet<string> { "A", "B", "C" };
bool containsA = hashSet.Contains("A"); // True
HashSet 是一个提供快速查找特定元素是否存在的集合。 它就像收藏界的 google,只是速度更快!
用例:
当需要频繁检查集合是否包含某个元素时
从集合中删除重复项
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> evenNumbers = list.Where(x => x % 2 == 0);
LINQ 提供了一种强大的声明性方式来查询集合。 只需一行代码,您就可以进行过滤、排序、转换等等。 这就像您的收藏有一位私人助理!
用例:
当需要对集合执行复杂操作时
对集合进行过滤或排序
ObservableCollection<string> collection = new ObservableCollection<string>();
collection.CollectionChanged += (s, e) => { /* Handle change */ };
collection.Add("A");
可观察集合使您可以轻松地对集合中的更改做出反应。 这就像每当有人发布新的猫视频时都会收到通知!
用例:
当您需要根据集合中的更改更新 UI 时
记录对集合的更改
ConcurrentDictionary<int, string> concurrentDictionary = new ConcurrentDictionary<int, string>();
System.Collections.Concurrent 命名空间提供了多个可以在多个线程中安全使用的集合。 这使您不必处理锁和其他同步原语。 它就像一个预先打包的、无麻烦的多线程解决方案!
用例:
当需要从多个线程访问集合时
避免手动同步
class MyComparer : IComparer<int>
{
public int Compare(int x, int y)
{
// Reverse order
return y.CompareTo(x);
}
}
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
list.Sort(new MyComparer());
IComparer<T> 和 IEqualityComparer<T> 接口允许您自定义元素的比较方式以及它们是否被视为相等。 这就像决定自己的游戏规则一样!
用例:
当您需要以特定方式对集合进行排序时
根据特定标准比较元素
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
var groups = list.GroupBy(x => x % 2 == 0 ? "Even" : "Odd");
GroupBy 方法允许您根据特定标准对元素进行分组。 这就像按颜色和尺寸整理袜子抽屉一样!
用例:
当您需要根据特定标准对元素进行分组时
对每个组分别进行操作
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
bool anyEven = list.Any(x => x % 2 == 0); // True
bool allPositive = list.All(x => x > 0); // True
Any 和 All 方法提供了一种声明性方式来检查集合中的任何或所有元素是否满足条件。 这就像快速检查盒子里是否还有巧克力,或者篮子里的所有苹果是否都熟了!
用例:
当您需要检查任何或所有元素是否满足条件时
避免手动编写循环
Action<int> action1 = x => Console.WriteLine($"Action 1: {x}");
Action<int> action2 = x => Console.WriteLine($"Action 2: {x}");
Action<int> combined = action1 + action2;
combined(5); // Executes both actions
您可以将多个委托合并为一个多播委托。 这就像邀请所有朋友参加同一个聚会!
用例:
当你想通知多个监听者时
简化执行多个回调的代码
public class WeakEventHandler<TEventArgs>
{
private readonly WeakReference _targetReference;
private readonly MethodInfo _method;
public WeakEventHandler(EventHandler<TEventArgs> eventHandler)
{
_targetReference = new WeakReference(eventHandler.Target);
_method = eventHandler.Method;
}
public void Invoke(object sender, TEventArgs e)
{
if (_targetReference.IsAlive)
_method.Invoke(_targetReference.Target, new object[] { sender, e });
}
}
即使事件源仍然存在,弱事件模式也允许对侦听器进行垃圾收集。 这就像在没有人注意到的情况下离开聚会一样!
用例:
当您想避免长期对象中的内存泄漏时
确保短命监听器不会延长监听器的寿命
public delegate TResult MyFunc<T1, T2, TResult>(T1 arg1, T2 arg2);
您可以定义适用于任何类型的通用委托。 它就像代表代表类型的瑞士军刀!
用例:
当您需要一个适用于不同类型的委托时
编写更多可重用且类型安全的代码
public class MyEventArgs : EventArgs
{
public string Message { get; set; }
}
public class MyClass
{
public event EventHandler<MyEventArgs> MyEvent;
protected virtual void OnMyEvent(string message)
{
MyEvent?.Invoke(this, new MyEventArgs { Message = message });
}
}
您可以定义自定义 EventArgs 以提供有关事件的更多信息。 这就像发送详细的报告而不是简短的通知!
用例:
当您需要提供活动的附加信息时
创建更具表现力和信息量的活动
Func<object> objectFunc = () => new object();
Func<string> stringFunc = objectFunc; // Covariance
Action<string> stringAction = str => Console.WriteLine(str);
Action<object> objectAction = stringAction; // Contravariance
协变和逆变允许您以保留类型兼容性的方式分配委托。 这就像将方钉安装到圆孔中,但是以类型安全的方式!
用例:
当您需要互相分配代表时
创建更灵活且可重用的委托代码
Func<int, int> square = delegate(int x) { return x * x; };
您可以匿名定义委托,而无需声明单独的方法。 这就像创建一家快闪店而不是一家永久性商店!
用例:
当您想内联定义委托时
让委托代码靠近使用它的地方
Func<int, int> slowFunc = x => { Thread.Sleep(1000); return x * x; };
IAsyncResult asyncResult = slowFunc.BeginInvoke(5, null, null);
// Do other work...
int result = slowFunc.EndInvoke(asyncResult); // Waits for the result
您可以使用 BeginInvoke 和 EndInvoke 方法异步执行委托。 这就像写信而不是打电话一样!
用例:
当您需要执行长时间运行的操作时
让您的 UI 保持响应能力
class MyClass
{
private Func<int, int> _myFunc = x => x * x;
public void SetFunc(Func<int, int> func)
{
_myFunc = func;
}
public int Compute(int x)
{
return _myFunc(x);
}
}
您可以使用委托作为实例变量来创建高度可定制的类。 这就像在汽车行驶时更换发动机一样!
用例:
当您需要自定义类的行为时
创建灵活且可扩展的类
public class MyClass
{
public event EventHandler<string> MyEvent;
protected virtual void OnMyEvent(string value)
{
MyEvent?.Invoke(this, value);
}
}
EventHandler<T> 委托提供了声明事件的标准方法。 这就像在活动中普遍接受的握手!
用例:
当你需要声明一个事件时
确保您的事件与 .NET 约定兼容
Func<int, bool> isEven = x => x % 2 == 0;
List<int> numbers = Enumerable.Range(0, 10).ToList();
List<int> evenNumbers = numbers.Where(isEven).ToList();
委托是封装表达式并传递它们的好方法。 这就像在你的口袋里携带一个便携式数学方程!
用例:
当您需要传递复杂的表达式时
让您的代码更具表现力和灵活性
try
{
// Potentially dangerous code here...
}
catch (SpecificException ex)
{
// Handle a specific exception
}
catch
{
// Handle any other exceptions
}
finally
{
// Cleanup code that always executes
}
经典的 try-catch-finally 语句。 它就像一张安全网,可以防止任何意外的空中飞人跌倒!
用例:
执行可能抛出异常的代码时
确保清理代码始终运行
catch (Exception ex)
{
throw new MyException("Something bad happened", ex);
}
使用附加信息重新引发异常。 这就像退回有缺陷的产品,但附有投诉信!
用例:
当您需要向异常添加附加信息时
创建详细的异常历史记录
catch (Exception ex) when (ex.Message.Contains("specific"))
{
// Handle the exception
}
根据条件过滤异常。 它就像一个例外的保镖,只允许某些人进入!
用例:
当你只想处理某些异常时
创建更具可读性和更高效的异常处理代码
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
}
访问异常的内部异常。 就像剥洋葱,露出它的层一样!
用例:
当您需要发现异常的根本原因时
显示或记录更详细的异常信息
try
{
// Parallel or async code that throws multiple exceptions...
}
catch (AggregateException ae)
{
ae.Handle(ex =>
{
// Handle each exception
return true;
});
}
处理从并行或异步代码引发的多个异常。 就像一张网捕捉一群蜜蜂一样!
用例:
执行可能引发多个异常的并行或异步代码时
单独处理每个异常
try
{
// Dangerous code...
}
catch (Exception ex) when (LogException(ex))
{
}
bool LogException(Exception ex)
{
// Log the exception and return false
return false;
}
记录异常而不捕获它们。 就像闭路电视摄像机观察一切但不干预!
用例:
当您需要记录异常但允许它们传播时
监视代码中的异常
ExceptionDispatchInfo capturedException;
try
{
// Dangerous code...
}
catch (Exception ex)
{
capturedException = ExceptionDispatchInfo.Capture(ex);
}
// Later...
capturedException?.Throw();
捕获并重新抛出异常,同时保留原始堆栈跟踪。 这就像一个例外的时间胶囊!
用例:
当您需要跨线程或异步方法抛出异常时
保留异常的原始堆栈跟踪
public class MyException : Exception
{
public MyException(string message) : base(message) { }
public MyException(string message, Exception inner) : base(message, inner) { }
}
为特定错误场景创建自定义异常。 这就像为特定的亡命徒制作一张通缉海报!
用例:
当您需要在代码中表示特定的错误条件时
创建更具表现力和更详细的例外
catch (Exception ex)
{
if (ex.Source == "MyAssembly")
{
// Handle the exception
}
}
检查异常的来源。 这就像追踪电话的来源一样!
用例:
当您需要处理来自特定来源的异常时
区分来自不同程序集或类的异常
public class MyController : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
// Handle exceptions for the entire controller
}
}
处理整个 MVC 控制器的异常。 就像建筑物的安全检查员一样!
用例:
当您想要处理 MVC 控制器中的所有异常时
将异常处理代码集中在 MVC 应用程序中