c# ArgumentOutOfRangeException
ArgumentOutOfRangeException 是 C# 中表示某个参数值超出了方法或属性定义的有效范围时引发的一个异常。这个异常通常在尝试访问数组、集合、字符串等的无效索引,或者当传递给方法或属性的参数不在其有效范围内时发生。
例如,如果你有一个方法,它接受一个整数参数 index,并且这个参数应该在一个特定的范围内(比如 0 到数组的长度减一),但是调用者传递了一个超出这个范围的 index 值,那么这个方法就应该抛出一个 ArgumentOutOfRangeException。
下面是一个简单的例子,演示了如何引发 ArgumentOutOfRangeException:
csharp
public class ExampleClass
{
private int[] array = new int[5]; // 假设数组长度为5
public void SetValue(int index, int value)
{
if (index < 0 || index >= array.Length)
{
throw new ArgumentOutOfRangeException(nameof(index), "Index must be within the bounds of the array.");
}
array[index] = value;
}
}
// 使用示例
class Program
{
static void Main()
{
ExampleClass example = new ExampleClass();
try
{
example.SetValue(6, 42); // 引发 ArgumentOutOfRangeException,因为索引 6 超出了数组的范围
}
catch (ArgumentOutOfRangeException ex)
{
Console.WriteLine(ex.Message); // 输出异常信息
}
}
}
在这个例子中,SetValue 方法检查传入的 index 是否在数组的有效范围内。如果不在,就抛出一个 ArgumentOutOfRangeException,并指定哪个参数(nameof(index))以及一个描述性的错误消息。在 Main 方法中,我们尝试使用超出范围的索引来调用 SetValue 方法,并使用 try-catch 块来捕获并处理这个异常。
c# .?
在C#中,?. 是一个称为"null 条件运算符"(Null-conditional Operator)或"Elvis Operator"的运算符。这个运算符提供了一种简洁的方式来检查对象是否为null,并在不为null的情况下调用其成员。如果左侧的操作数为null,则整个表达式的结果为null,而不会引发NullReferenceException。
这里有一些使用?.运算符的示例:
csharp
// 假设我们有一个可能为null的对象customer
Customer customer = GetCustomer();
// 使用null条件运算符来安全地访问Name属性
string name = customer?.Name; // 如果customer为null,则name为null,否则为customer.Name的值
// 嵌套使用null条件运算符
string address = customer?.Address?.Street; // 如果customer或Address为null,则address为null
// 与null合并运算符(??)结合使用,以提供默认值
string displayName = customer?.Name ?? "Unknown Customer"; // 如果customer为null或Name为null,则displayName为"Unknown Customer"
// 调用方法(如果对象不为null)
int? result = customer?.CalculateSomething(); // 如果customer为null,则result为null,否则为CalculateSomething的返回值
// 访问索引器(如果对象不为null)
int? firstChar = customer?.Name?[0]; // 如果customer或Name为null,或Name没有第一个字符,则firstChar为null
// 分配值(如果对象不为null)
customer?.SomeProperty = newValue; // 如果customer不为null,则设置SomeProperty的值为newValue
请注意,?.运算符不会执行短路评估(short-circuiting)来避免后续操作中的null引用,它仅检查左侧操作数是否为null。如果你需要基于多个条件来避免null引用,你可能需要链式地使用多个?.运算符或使用其他逻辑来控制流程。
此外,?.运算符不会改变左侧操作数的值或状态,它只是提供了一个安全的方式来访问成员或调用方法,而不会导致NullReferenceException。
c# CancellationToken
在C#中,CancellationToken是一个非常重要的类,主要用于表示操作的取消请求。它通常与异步编程和长时间运行的操作一起使用,以提供一种优雅的方式来取消这些操作。
以下是关于CancellationToken的一些关键点和用法:
来源:
CancellationToken通常通过CancellationTokenSource创建。CancellationTokenSource允许你发出取消信号。
你也可以在需要取消操作时传递预定义的取消令牌,如CancellationToken.None(表示没有取消请求)或来自其他源的令牌。
使用:
在执行异步操作(如使用Task或Task)时,你可以接受一个CancellationToken参数。
当调用者决定取消操作时,它会调用CancellationTokenSource.Cancel方法,这会设置CancellationToken的IsCancellationRequested属性为true。
执行操作的方法应该定期检查CancellationToken.IsCancellationRequested属性,并在收到取消请求时适当地响应。
响应取消:
当操作检测到取消请求时,它应该停止正在执行的工作,并(尽可能)清理其资源。
通常,可以通过抛出一个OperationCanceledException来响应取消请求,但这不是强制的。重要的是要优雅地停止操作并释放资源。
传播取消:
如果一个操作创建了其他操作或任务,并且这些操作或任务也应该在原始操作被取消时取消,那么原始操作的取消令牌应该传递给这些子操作或任务。
超时:
CancellationToken经常与超时一起使用。你可以使用CancellationTokenSource.CancelAfter方法来指定一个超时时间。
监听取消:
你可以使用CancellationToken.Register方法来注册一个回调,当取消令牌被取消时,该回调会被调用。
注意事项:
不要在取消令牌被取消后继续使用它。一旦令牌被取消,它就不能再被重置或再次使用。
确保在操作被取消时正确释放所有资源。
以下是一个简单的示例,演示了如何使用CancellationToken和CancellationTokenSource:
csharp
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var cts = new CancellationTokenSource();
// 模拟一个长时间运行的操作
var task = Task.Run(() => LongRunningOperation(cts.Token), cts.Token);
// 等待一段时间,然后取消操作
await Task.Delay(2000); // 等待2秒
cts.Cancel();
try
{
await task; // 等待操作完成(或抛出异常)
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation was canceled.");
}
}
static void LongRunningOperation(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Cancellation requested.");
// 清理资源(如果有的话)并退出方法
return;
}
Thread.Sleep(500); // 模拟工作
Console.WriteLine("Working...");
}
}
}
c# IEnumerable
在C#中,IEnumerable 是一个特定的泛型接口,它继承自非泛型的 IEnumerable 接口,并专门用于表示可以枚举的整数集合。这个接口定义了一个 GetEnumerator() 方法,该方法返回一个 IEnumerator 类型的对象,该对象用于遍历集合中的整数。
IEnumerable 接口通常在处理整数集合的场景中使用,比如当你需要遍历一个整数数组、列表(List)或者其他实现了 IEnumerable 接口的自定义集合时。
下面是一个简单的示例,展示了如何使用 IEnumerable:
csharp
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// 创建一个整数列表
List numbers = new List { 1, 2, 3, 4, 5 };
// 因为List<int>实现了IEnumerable<int>接口,所以可以直接遍历
foreach (int number in numbers)
{
Console.WriteLine(number);
}
// 创建一个返回IEnumerable<int>的方法
IEnumerable<int> evenNumbers = GetEvenNumbers(10);
// 遍历返回的IEnumerable<int>
foreach (int evenNumber in evenNumbers)
{
Console.WriteLine(evenNumber);
}
}
// 一个返回IEnumerable<int>的方法
static IEnumerable<int> GetEvenNumbers(int count)
{
for (int i = 0; i < count; i += 2)
{
yield return i; // 使用迭代器块(yield return)来返回一系列整数
}
}
}
在上面的示例中,我们首先创建了一个 List 对象,并填充了一些整数。由于 List 实现了 IEnumerable 接口,我们可以直接使用 foreach 循环来遍历它。
然后,我们定义了一个名为 GetEvenNumbers 的方法,它返回一个 IEnumerable。这个方法使用迭代器块(yield return)来生成一个包含偶数的序列。在 Main 方法中,我们调用 GetEvenNumbers 方法,并使用 foreach 循环来遍历返回的偶数序列。
通过使用 IEnumerable,我们可以很容易地创建和遍历整数集合,而不必关心这些集合的具体实现细节。这使得代码更加灵活和可重用。
string.Join
string.Join 是C#中 System.String 类的一个静态方法,用于将多个字符串按照指定的分隔符连接成一个新的字符串。这个方法接受两个参数(或更多,取决于重载版本):
分隔符(separator):用于连接各个元素的字符串。
字符串数组或可迭代集合(values):要连接的字符串的集合。
以下是 string.Join 方法的基本用法示例:
csharp
using System;
class Program
{
static void Main()
{
string[] words = { "Hello", "World", "!" };
string sentence = string.Join(" ", words); // 使用空格作为分隔符
Console.WriteLine(sentence); // 输出: Hello World !
string commaSeparated = string.Join(",", words); // 使用逗号作为分隔符
Console.WriteLine(commaSeparated); // 输出: Hello,World,!
// 也可以使用其他类型的可迭代集合,如List<string>
List<string> listWords = new List<string> { "Hello", "World", "!" };
string listSentence = string.Join(" ", listWords);
Console.WriteLine(listSentence); // 输出: Hello World !
}
}
除了接受字符串数组或 IEnumerable 作为参数之外,string.Join 方法还有其他重载版本,可以接受其他类型的集合,只要这些集合的元素可以隐式转换为字符串。
注意:当使用 string.Join 连接字符串时,如果源集合(如数组或列表)是 null,string.Join 方法将返回一个空字符串,而不是抛出异常。但是,如果源集合中的某个元素是 null,那么 null 将被视为空字符串进行连接。