Skip to content

C# - 其他运算符

C# - 其他运算符(Miscellaneous Operators)

Section titled “C# - 其他运算符(Miscellaneous Operators)”

除了标准的算术和逻辑运算符之外,C# 还提供了一组强大的其他运算符,用于类型检查、null 处理和条件赋值等任务。掌握这些运算符可以使你的代码更简洁、可读性更高且更健壮。

运算符名称描述示例
?:三元条件运算符(Ternary Conditional)一个简洁的 if-else 语句。age >= 18 ? "Adult" : "Minor";
??空值合并运算符(Null-Coalescing)如果左侧操作数不为 null,则返回左侧操作数;否则,返回右侧操作数。string name = userInput ?? "Default";
??=空值合并赋值运算符(Null-Coalescing Assignment)仅当左侧操作数为 null 时,才将右侧操作数赋值给左侧操作数。myList ??= new List<int>();
is类型检查 / 模式匹配(Type Check / Pattern Matching)检查对象是否为特定类型,并可将其赋值给新变量。if (obj is string s) { ... }
as安全类型转换(Safe Type Cast)将对象转换为指定类型;如果转换失败,则返回 null 而不是抛出异常。var str = obj as string;
typeof()获取类型对象(Get Type Object)返回类型对应的 System.Type 对象。Type t = typeof(int);
sizeof()获取大小(Get Size)返回值类型(value type)的字节大小。需要 unsafe 上下文。sizeof(int); // 返回 4

使用三元运算符进行简单的一行条件赋值。它比完整的 if-else 块更紧凑。

int temperature = 25;
string weather = temperature > 20 ? "Warm" : "Cold";
Console.WriteLine($"The weather is {weather}."); // 输出: The weather is Warm.

这些运算符对于安全处理 null 值和提供默认值至关重要。

// 使用 '??' 提供默认值
string? nameFromApi = null;
string displayName = nameFromApi ?? "Guest";
Console.WriteLine($"Welcome, {displayName}!"); // 输出: Welcome, Guest!
// 使用 '??=' 仅在为 null 时才初始化列表
List<string>? userRoles = null;
userRoles ??= new List<string>();
userRoles.Add("Admin");
Console.WriteLine($"User has {userRoles.Count} role(s)."); // 输出: User has 1 role(s).

is 运算符已演变为强大的模式匹配工具。它是检查对象类型的现代、首选方法。

void PrintObjectInfo(object obj)
{
// 现代模式匹配与 'is'
if (obj is string s)
{
Console.WriteLine($"It's a string with length: {s.Length}");
}
else if (obj is int i)
{
Console.WriteLine($"It's an integer with value: {i}");
}
else if (obj is null)
{
Console.WriteLine("The object is null.");
}
else
{
Console.WriteLine($"It's an unknown type: {obj.GetType().Name}");
}
}
PrintObjectInfo("Hello C#"); // It's a string with length: 8
PrintObjectInfo(42);
PrintObjectInfo(null);

当你需要尝试可能失败的类型转换时,请使用 as 运算符。它比直接转换 (TypeName)obj 更安全,因为它不会抛出 InvalidCastException 异常。

object someValue = "This is a string";
object anotherValue = 123;
// 成功转换
string? result1 = someValue as string;
Console.WriteLine($"Result 1: {result1 ?? "Cast failed"}"); // 输出: Result 1: This is a string
// 转换失败 - 返回 null
string? result2 = anotherValue as string;
Console.WriteLine($"Result 2: {result2 ?? "Cast failed"}"); // 输出: Result 2: Cast failed

C# 还支持用于高性能或互操作性场景的指针相关运算符。这些只能在 unsafe 上下文中使用,并且通常应避免在通用应用程序代码中使用。

  • sizeof():返回值类型(value type)的字节大小。用于内存分配。
  • & (取地址运算符):获取变量的内存地址。
  • * (指针解引用运算符):声明一个指针或解引用它以获取其地址处的值。
Console.WriteLine("Demonstrating 'sizeof' operator:");
// 'sizeof' 对于某些类型必须在 unsafe 上下文中,但对于原始类型是安全的。
Console.WriteLine($"The size of int is {sizeof(int)} bytes.");
Console.WriteLine($"The size of double is {sizeof(double)} bytes.");

警告: 编写 unsafe 代码会绕过 .NET 运行时(runtime)的安全保证。仅在绝对必要时使用它,并对内存管理有深入的理解。

  • 优先使用模式匹配(is):对于类型检查,优先选择 if (obj is TypeName variable) 而不是使用 as 后跟 null 检查。它更简洁、更具表达力。
  • 拥抱空值合并:使用 ?? 和 ??= 编写更清晰、更健壮的代码来处理潜在的 null 值。它远优于冗长的 if (variable == null) 检查。
  • 简单情况使用三元运算符:?: 运算符非常适合简单的条件赋值,但要避免嵌套它们,因为它很快就会变得难以阅读。
  • 避免使用 unsafe 代码:只在性能关键的互操作或低级算法中才使用 unsafe 上下文,并且务必隔离该代码。