【C#基础】C# 运算符总结

简介: 编程语言 C# 运算符的总结介绍。
序号 系列文章
1 【C#基础】C# 基础语法解析
2 【C#基础】C# 数据类型总结

前言

:smile:大家好,我是writer桑,前面一章已经学习了 C# 中变量和常量的使用,那本章就开始学习 C# 程序中的运算符概念,希望看完大家能够有所收获,感谢支持!

运算符

运算符是一种告诉编译器执行特定行为的数学或逻辑操作的符号。C# 内置了许多类型的运算符,用于对这些类型的值执行一些基本的操作。这些运算符包括:算术运算符、比较运算符、布尔逻辑运算符、位运算符和相等运算符。

1,算术运算符

以下表格展示了一元运算符,其中假设变量 a 等于10:

一元运算符 描述 实例
++ 增量运算符 ++a 输出 11
-- 减量运算符 --a 输出 9
+ 一元加运算符 +a 输出 10
- 一元减运算符 -a 输出 -10

1.1,增量和减量运算符:

增量运算符 ++ 按 1 递增起操作数。操作数必须是变量、属性访问或索引器访问。其中增量运算符以两种形式进行支持: 前缀增量运算符 ++x 表示先递增再赋值和后缀增量运算符 x++ 表示先赋值再递增; 而减量运算符和增量运算符很类似,只不过是 + 号换成 - 号,把增量换成减量,主要的作用都是一样的。 这里借增量运算符来讨论。

示例如下:

int a = 10;
int b = 10;

// 后缀增量运算符 
Console.WriteLine(a++);     // 输出 10  
Console.WriteLine(a);       // 输出 11
// 前缀增量运算符 
Console.WriteLine(++b);     // 输出 11

int c = 10;
int d = 10;

// 后缀减量运算符 
Console.WriteLine(c--);     // 输出 10  
Console.WriteLine(c);       // 输出 9
// 前缀减量运算符 
Console.WriteLine(--d);     // 输出 9 

1.2,一元加和减运算符:

一元 + 运算符表示对其操作数取正,也就是返回其操作数的值,一元 - 运算符对其操作数取负,也就是返回其操作数的负值。

示例如下:

Console.WriteLine(+4);      // 输出 4
Console.WriteLine(-4);      // 输出 -4
Console.WriteLine(-(-4));   // 输出 4
uint a = 5;
var b = -a;

Console.WriteLine(b);   // 输出 -5
Console.WriteLine(b.GetType()); // 输出 System.Int64
Console.WriteLine(-double.NaN); // 输出 NaN 

以下表格展示了二元运算符,其中假设变量 a 等于10,变量 b 等于 20:
| 二元运算符 | 描述 | 实例|
|:--:|:--:|:--:|
|| 乘法运算符 | a b 输出 200|
|/| 除法运算符 | b / a 输出 2|
| %| 余数运算符 |b % a 输出 0 |
| +| 加法运算符 |b + a 输出 30 |
| -| 减法运算符 | b - a 输出 10 |

1.3,乘法运算符:

乘法运算符 表示计算其操作数的乘积,在不安全的上下文中, 一元 运算符还可以表示指针间接运算符。

示例如下:

Console.WriteLine(5 * 2);           // 输出 10
Console.WriteLine(0.5 * 2.5);       // 输出 1.25
Console.WriteLine(0.1m * 23.4m);    // 输出 2.34 
//  不安全的上下文 
unsafe
{
    char letter = 'A';
    char* pointerToLetter = &letter;
    Console.WriteLine(pointerToLetter);
    Console.WriteLine($"Value of the `letter` variable: {letter}");
    Console.WriteLine($"Address of the `letter` variable:{ (long)pointerToLetter:X}");
}

1.4,除法运算符:

除法运算符 / 表示计算其操作数之间相除的商,整数类型的操作数,/ 运算符的结果为整数类型,并且等于两个操作数之商项向零舍入后的结果;若想要商的结果为浮点数形式,则需要使用浮点类型的操作数。

示例如下:

Console.WriteLine(13 / 5);         // 输出 2
Console.WriteLine(-13 / 5);     // 输出 -2
Console.WriteLine(13 / -5);     // 输出 -2
Console.WriteLine(-13 / -5);     // 输出 2 
//  浮点数形式 
Console.WriteLine(13 / 5.0);     // 输出 2.6

int a = 13;
int b = 5;
Console.WriteLine((double)a / b);     // 输出 2.6

1.5,余数运算符:

余数运算符 % 表示计算左侧操作数除以右侧操作数后的余数。 整数类型的操作数,a % b 的结果是 a - (a / b) * b 得出的值。 非零余数的符号与左侧操作数的符号相同。

示例如下:

Console.WriteLine(5 % 4);       // 输出 1
Console.WriteLine(5 % -4);      // 输出 1
Console.WriteLine(-5 % 4);      // 输出 -1
Console.WriteLine(-5 % -4);     // 输出 -1 

1.6,加法运算符:

加法运算符 + 表示计算操作数之间的和,同时 + 运算符还可以用于字符串串联和委托组合。

示例如下:

Console.WriteLine(5 + 4);       // 输出 9
Console.WriteLine(5 + 4.3);     // 输出 9.3
Console.WriteLine(5.1m + 4.2m); // 输出 9.3 
// 字符串串联
Console.WriteLine("Hello" + "World");    // Hello World
// 委托组合
Action a = () => Console.Write("a");
Action b = () => Console.Write("b");
Action ab = a + b;
ab();   // 输出:ab 

1.7,减法运算符:

减法运算符 - 表示从其左侧操作数中减去其右侧操作数,同时 - 运算符还可以删除委托。

示例如下:

Console.WriteLine(47 - 3);      // 输出 44
Console.WriteLine(5 - 4.3);     // 输出 0.7
Console.WriteLine(7.5m - 2.3m); // 输出 5.2
// 删除委托
Action a = () => Console.Write("a");
Action b = () => Console.Write("b");
Action ab = a + b - b;
ab();         // 输出:a

2,布尔逻辑运算符

以下表格展示了布尔逻辑运算符,其中假设变量 a 为 true,变量 b 为 false:

布尔运算符 描述 实例
! 逻辑非运算符 !a 为 False
& 逻辑与运算符 a & b 为 False
\ 逻辑或运算符 a \ b 为 True
^ 逻辑异或运算符 a ^ b 为 True
&& 条件逻辑与运算符 a && b 为 False
\ \ 条件逻辑或运算符 a \ \ b 为 True

2.1,逻辑非运算符:

一元前缀运算符 ! 表示计算操作数的逻辑非。也就是说,如果操作数的计算结果为false,它生成true,相对的如果操作数的计算结果为 true,它生成 false;同时一元后缀运算符 !表示 null 包容运算符或 null 抑制运算符,可以在已启用的可为空的注释上下文中,来取消上述表达式的所有可为 null 警告。

示例如下:

bool passed = false;
Console.WriteLine(!passed);     // 输出:True 
Console.WriteLine(!true);       // 输出:False
public static void Main()
{
    Person? p = Find("John");
    if (IsValid(p))
    {
        Console.WriteLine($"Found {p!.Name}");
    }
}

public static bool IsValid(Person? person)
 => person is not null && person.Name is not null;


// 如果肯定某个表达式不能为 null,但编译器无法识别它,
// 可以使用 null 包容运算符。在此示例中,如果 IsValid 方法返回 true,
// 则其参数不是 null,可以放心取消对它的引用。

2.2,逻辑与运算符:

逻辑与运算符 & 表示计算操作数的逻辑与。 只有当 x 和 y 的计算结果都为 true,则 x & y 的输出结果才为 true。 否则,其它结果全为 false。 注意即使左侧操作数计算结果为 false,& 运算符也会计算这两个操作数;对于整型数值类型的操作数,& 运算符计算其操作数的位逻辑 AND;一元 & 运算符会返回其操作数的地址。

示例如下:

// 逻辑非运算
Console.WriteLine(true & true);     // 输出:True 
Console.WriteLine(false & true);    // 输出: False 
// 位逻辑 AND 运算
Console.WriteLine(1 & 0);     // 输出:0 
// 不安全的上下文
unsafe
{
    // 一元 & 运算符返回其操作数的地址
    int number = 27;
    int* pointerToNumber = &number;
    Console.WriteLine($"变量值: {number}");
    Console.WriteLine($"变量地址: {(long)pointerToNumber:X}");
}

2.3,逻辑或运算符:

逻辑或运算符 | 表示计算操作数的逻辑或。如果 x 或 y 的计算结果为 true,则 x | y 的结果为 true,否则,其它结果全为false。即使左侧操作数计算结果为 true,| 运算符也会计算这两个操作数;对于整型数值类型的操作数,| 运算符会计算其操作数的位逻辑 OR。

示例如下:

// 逻辑或运算
Console.WriteLine(true | false);     // 输出:True 
Console.WriteLine(false & false);    // 输出: False 
// 位逻辑 OR 运算
Console.WriteLine(1 & 0); // 输出 0

2.4,逻辑异或运算符:

逻辑异或运算符 ^ 表示计算操作数的逻辑异或(亦称为“逻辑 XOR”)。当 x 的布尔值和 y 的布尔值不相等时,那么 x ^ y 的结果为 true。 否则,其它结果全为 false。 也就是说,对于 bool 操作数,^ 运算符的计算结果与不等运算符 != 相同;同时对于整型数值类型的操作数,^ 运算符计算其操作数的位逻辑异或。

示例如下:

// 逻辑异或运算 
Console.WriteLine(true ^ false);
Console.WriteLine(true ^ true);
Console.WriteLine(false ^ false);
// 位逻辑异或运算
Console.WriteLine(1 ^ 0);   // 输出: 1

2.5,条件逻辑与运算符:

条件逻辑与运算符 &&(亦称为“短路”逻辑与运算符)表示计算操作数的逻辑与。 如果 x 和 y 的计算结果都为 true,则 x && y 的结果为 true, 否则,其它结果都为 false;和逻辑与运算符 & 不同的是如果 && 运算符左侧操作数 x 的计算结果为 false,那么就不执行右侧操作数 y 的计算结果。

示例如下:

using System;

public class Program
{
    static bool SecondOperand()
    {
        Console.WriteLine("对第二个操作数求值。");
        return true;
    }

    static void Main()
    {
        bool a = false && SecondOperand();  // 左侧为false, 不会执行 SecondOperand 方法的操作 
        Console.WriteLine(a);               // 输出:False

        bool b = true && SecondOperand();   // 输出:对第二个操作数求值。 
        Console.WriteLine(b);   // True  
    } 

}

2.6,条件逻辑或运算符:

条件逻辑或运算符 ||(亦称为“短路”逻辑或运算符)表示计算操作数的逻辑或。 如果 x 或 y 的计算结果为 true,则 x || y 的结果为 true。 否则,其它结果都为 false;和逻辑或运算符 | 不同的是如果 || 运算符左侧操作数 x 的计算结果为 true,则不执行右侧操作数 y 的计算结果。

示例如下:

using System;

public class Program
{
    static bool SecondOperand()
    {
        Console.WriteLine("对第二个操作数求值。");
        return false;
    }

    static void Main()
    {
        bool a = true || SecondOperand();   // 左侧为true, 不会执行 SecondOperand 方法的操作 
        Console.WriteLine(a);               // 输出:True

        bool b = false || SecondOperand();   // 输出:对第二个操作数求值。 
        Console.WriteLine(b);                // 输出:false
    }

}

3,位运算符

以下表格展示了位运算符和移位运算符,其中假设变量 a 为 1,变量 b 为 2:

位运算符 描述 实例
~ 按位求补运算符 ~a 等于 -2
<< 左移位运算符 a << 2 等于 4
>> 右移位运算符 a >> 2 等于 0
>>> 无符号右移运算符 a >>> 2 等于 0
& 逻辑与运算符 a & b 等于 0
^ 逻辑异或运算符 a ^ b 等于 3
\ 逻辑或运算符 a \ b 等于 3

3.1,按位求补运算符:

~ 运算符表示通过反转每个位产生其操作数的按位求补; 同时也可以使用 ~ 符号来声明终结器(也就是折构函数)。

示例如下:

uint a = 0b_0000_1111_0000_1111_0000_1111_0000_1100;
uint b = ~a; 

Console.WriteLine(Convert.ToString(b, toBase: 2));  // 输出: 11110000111100001111000011110011
// 终结器的简单实例 
class Car
{
    ~Car()      
    {
        // 清理语句....
    }
}

3.2,左移位运算符:

<< 运算符表示将其左侧操作数向左移动右侧操作数定义的位数。 有关右侧操作数如何定义移位计数的信息,同时左移运算放弃超出结果类型范围的高阶位,并将低阶空位位置设置为零,也就是高位舍弃,低位补零。

示例如下:

uint x = 0b_1100_1001_0000_0000_0000_0000_0001_0001;
Console.WriteLine($"之前: {Convert.ToString(x, toBase: 2)}");

uint y = x << 4;
Console.WriteLine($"之后: {Convert.ToString(y, toBase: 2)}");

// 输出:
// 之前: 11001001000000000000000000010001
// 之后: 10010000000000000000000100010000 

3.3,右移位运算符:

\>> 运算符表示将其左侧操作数向右移动右侧操作数定义的位数,右移位运算会放弃低阶位。而高顺序空位位置是根据左侧操作数类型设置的:当左侧操作数的类型是 int 或 long 时,如果左侧操作数为非负,高顺序空位位置设置为0, 如果为负, 则将该位置设置为1; 当左侧操作数的类型是 uint 或 ulong时,则高顺序空位位置始终设置为0。

示例如下:

// int类型 
int a = int.MinValue;
Console.WriteLine($"之前: {Convert.ToString(a, toBase: 2)}");

int b = a >> 3;
Console.WriteLine($"之后: {Convert.ToString(b, toBase: 2)}");
// 输出:
// 之前: 10000000000000000000000000000000
// 之后: 11110000000000000000000000000000 
// uint 类型 
uint c = 0b_1000_0000_0000_0000_0000_0000_0000_0000;
Console.WriteLine($"之前: {Convert.ToString(c, toBase: 2),32}");

uint d = c >> 3;
Console.WriteLine($"之后: {Convert.ToString(d, toBase: 2).PadLeft(32,
'0'),32}");
// 输出: 
// 之前: 10000000000000000000000000000000
// 之后: 00010000000000000000000000000000 

3.4,无符号右移运算符:

无符号右移运算符 >>> 需要 C# 11 及更高的版本支持, 表示将其左侧操作数向右移动其右侧操作数定义的位数。>>> 运算符始终执行逻辑移位,也就是说无论左侧操作数的类型如何,高顺序空位位置始终设置为零。 如果左侧操作数是带符号类型,>> 运算符将执行算术移位(即最高有效位的值传播到高顺序空位位置)。

示例如下:

// 运算符 >> 和运算符 >>> 的区别: 
int x = -8;
Console.WriteLine($"之前: {x,11}, 十六进制: {x,8:x}, 二进制:{Convert.ToString(x, toBase: 2),32}");

int y = x >> 2;
Console.WriteLine($"之后 >>: {y,11}, 十六进制: {y,8:x}, 二进制:{Convert.ToString(y, toBase: 2),32}");

int z = x >>> 2;
Console.WriteLine($"之后 >>>: {z,11}, 十六进制: {z,8:x}, 二进制:{Convert.ToString(z, toBase: 2).PadLeft(32, '0'),32}");

// 输出:
// 之前: -8, 十六进制: fffffff8, 二进制: 11111111111111111111111111111000
// 之后 >>: -2, 十六进制: fffffffe, 二进制: 11111111111111111111111111111110
// 之后 >>>: 1073741822, 十六进制: 3ffffffe, 二进制: 00111111111111111111111111111110 

3.5,逻辑与运算符:

& 运算符表示计算其整型操作数的位逻辑 AND; 对 bool 操作数, & 运算符对其操作数执行逻辑 AND 运算;一元 & 运算符是 address-of 运算符。

示例如下:

uint a = 0b_1111_1000;
uint b = 0b_1001_1101;
uint c = a & b;

Console.WriteLine(Convert.ToString(c, toBase: 2));       // 输出: 10011000 

3.6,逻辑异或运算符:

^ 运算符表示计算其整型操作数的位逻辑异或,也称为位逻辑 XOR; 对于 bool 操作数,^ 运算符对其操作数执行逻辑异或运算。

示例如下:

uint a = 0b_1111_1000;
uint b = 0b_0001_1100;
uint c = a ^ b;

Console.WriteLine(Convert.ToString(c, toBase: 2));      // 输出:11100100  

3.7,逻辑或运算符:

| 运算符表示计算其整型操作数的位逻辑 OR; 对于 bool 操作数, | 运算符对齐操作数执行逻辑 OR 运算。

示例如下:

uint a = 0b_1010_0000;
uint b = 0b_1001_0001;
uint c = a | b;

Console.WriteLine(Convert.ToString(c, toBase: 2));       // 输出: 10110001

4,关系运算符

以下表格展示了相等运算符和比较运算符,其中假设变量 a 为 10,变量 b 为 20:

关系运算符 描述 实例
== 相等运算符 (a == b) 等于 False
!= 不等运算符 (a != b)等于 True
< 小于运算符 (a < b)等于 True
> 大于运算符 (a > b)等于 False
<= 小于或等于运算符 (a <= b)等于 True
>= 大于或等于运算符 (a >= b)等于 False

4.1,相等运算符:

相等运算符 == 表示测试两个对象是否相等。当内容相等时,值类型相等。当两个变量引用同一内存时,引用类型相等。

示例如下:

// 值类型的比较
int a = 1 + 2 + 3;
int b = 6;
Console.WriteLine(a == b);      // 输出: True

char c1 = 'a';
char c2 = 'A';
Console.WriteLine(c1 == c2);    // 输出: False
Console.WriteLine(c1 == char.ToLower(c2)); // 输出: True 
// 引用类型的比较
public class ReferenceTypesEquality
{
    public class MyClass
    {
        private int id;
        public MyClass(int id) => this.id = id;
    }

    public static void Main()
    {
        var a = new MyClass(1);
        var b = new MyClass(1);
        var c = a;

        Console.WriteLine(a == b);      // output: False
        Console.WriteLine(a == c);      // output: True
    }
}

4.2,不等运算符:

不等于运算符 != 表示当测试的两个对象不相等时,返回 true,否则返回 false。当内容不相等时,值类型不相等。当两个变量引用不同的内存时,引用类型不相等。

示例如下:

int a = 1 + 1 + 2 + 3;
int b = 6;
Console.WriteLine(a != b); // 输出:True

string s1 = "Hello";
string s2 = "Hello";
Console.WriteLine(s1 != s2); // 输出:False

object o1 = 1;
object o2 = 1;
Console.WriteLine(o1 != o2); // 输出:True 
// 引用类型的比较
public class ReferenceTypesEquality
{
    public class MyClass
    {
        private int id;
        public MyClass(int id) => this.id = id;
    }

    public static void Main()
    {
        var a = new MyClass(1);
        var b = new MyClass(1);
        var c = a;

        Console.WriteLine(a != b);      // 输出: True
        Console.WriteLine(a != c);      // 输出: False
    }
}

4.3,小于运算符:

小于运算符 < 表示如果左侧操作数小于右侧操作数,< 运算符返回 true,否则返回 false。

示例如下:

Console.WriteLine(7.0 < 5.1); // 输出: False
Console.WriteLine(5.1 < 5.1); // 输出: False
Console.WriteLine(0.0 < 5.1); // 输出: True
Console.WriteLine(double.NaN < 5.1); // 输出: False
Console.WriteLine(double.NaN >= 5.1); // 输出: False 

4.4,大于运算符:

大于运算符 > 表示如果左侧操作数大于右侧操作数,> 运算符返回 true,否则返回 false。

示例如下:

Console.WriteLine(7.0 > 5.1); // 输出: True
Console.WriteLine(5.1 > 5.1); // 输出: False
Console.WriteLine(0.0 > 5.1); // 输出: False
Console.WriteLine(double.NaN > 5.1); // 输出: False
Console.WriteLine(double.NaN <= 5.1); // 输出: False 

4.5,小于或等于运算符:

小于或等于运算符 <= 表示如果左侧操作数小于或等于右侧操作数,<= 运算符返回 true,否则返回 false。

示例如下:

Console.WriteLine(7.0 <= 5.1); // 输出: False
Console.WriteLine(5.1 <= 5.1); // 输出: True
Console.WriteLine(0.0 <= 5.1); // 输出: True
Console.WriteLine(double.NaN > 5.1); // 输出: False
Console.WriteLine(double.NaN <= 5.1); // 输出: False 

4.6,大于或等于运算符:

大于或等于运算符 >= 表示如果左侧操作数大于或等于右侧操作数,>= 运算符返回 true,否则返回 false。

示例如下:

Console.WriteLine(7.0 >= 5.1);      // 输出: True
Console.WriteLine(5.1 >= 5.1);      // 输出: True
Console.WriteLine(0.0 >= 5.1);      // 输出: False
Console.WriteLine(double.NaN < 5.1);    // 输出: False
Console.WriteLine(double.NaN >= 5.1);   // 输出: False  

5,赋值运算符

以下表格展示了赋值运算符,其中假设有变量 a 与 b:

赋值运算符 描述 实例
= 赋值运算符 a = b 等同于 b 赋值给 a
+= 加且赋值运算符 a += b 等同于 a = a + b
-= 减且赋值运算符 a -= b 等同于 a = a - b
*= 乘且赋值运算符 a = b 等同于 a = a b
/= 除且赋值运算符 a /= b 等同于 a = a / b
%= 求模且赋值运算符 a %= b 等同于 a = a % b
<<= 左移且赋值运算符 a <<= 2 等同于 a = a << 2
>>= 右移且赋值运算符 a >>= 2 等同于 a = a >> 2
&= 按位与且赋值运算符 a &= b 等同于 a = a & b
^= 按位异或且赋值运算符 a ^= b 等同于 a = a ^ b
\ = 按位或且赋值运算符 a \ = b 等同于 a = a \ b

5.1,赋值运算符:

赋值运算符 = 表示将其右操作数的值赋给变量、属性或由其左操作数给出的索引器元素。 赋值表达式的结果是分配给左操作数的值。 右操作数类型必须与左操作数类型相同,或可隐式转换为左操作数的类型。

示例如下:

var numbers = new List<double>() { 1.0, 2.0, 3.0 };
Console.WriteLine(numbers.Capacity);     

numbers.Capacity = 100; 
Console.WriteLine(numbers.Capacity);     
// 输出:
// 4
// 100

int newFirstElement;
double originalFirstElement = numbers[0];
newFirstElement = 5;
numbers[0] = newFirstElement;

Console.WriteLine(originalFirstElement);
Console.WriteLine(numbers[0]);
// 输出:
// 1
// 5

5.2,复合赋值:

对于二元运算符 op,符合赋值表达式 x op= y 等效于 x = x op y。上表中除了简单赋值运算符 = 之外的所有赋值运算符都可以用符合赋值表达式来概括。其中算术、布尔逻辑以及逻辑位和移位运算符支持复合赋值。

示例如下:

class Program
{
    static void Main(string[] args)
    {
        int a = 11;
        int b;

        b = a;
        Console.WriteLine("Line 1 - =  b 的值 = {0}", b);

        b += a;
        Console.WriteLine("Line 2 - += b 的值 = {0}", b);

        b -= a;
        Console.WriteLine("Line 3 - -=  b 的值 = {0}", b);

        b *= a;
        Console.WriteLine("Line 4 - *=  b 的值 = {0}", b);

        b /= a;
        Console.WriteLine("Line 5 - /=  b 的值 = {0}", b);

        b = 200;
        b %= a;
        Console.WriteLine("Line 6 - %=  b 的值 = {0}", b);

        b <<= 2;
        Console.WriteLine("Line 7 - <<=  b 的值 = {0}", b);

        b >>= 2;
        Console.WriteLine("Line 8 - >>=  b 的值 = {0}", b);

        b &= 2;
        Console.WriteLine("Line 9 - &=  b 的值 = {0}", b);

        b ^= 2;
        Console.WriteLine("Line 10 - ^=  b 的值 = {0}", b);

        b |= 2;
        Console.WriteLine("Line 11 - |=  b 的值 = {0}", b);
        Console.ReadLine();
    }
} 

6,其他运算符

以下表格展示了 C# 支持的其它一些运算符,其中假设变量 int? a = 10、int[] arr = {1}:

运算符 描述 实例
sizeof() sizeof 运算符 sizeof(int) 返回 4
typeof() typeof 运算符 typeof(StreamReader) 返回 System.IO.StreamReader
is is 运算符 (a is int) 返回 True
as as 运算符 (a as double?) 返回 null
? : 三元条件运算符 (true ? a : 0) 返回 10
??/??= Null 合并操作符 (a ?? 0) 返回 10
?. /?[] Null 条件运算符 arr?[0] 返回 1

6.1,sizeof 运算符:

sizeof 运算符表示返回给定类型的变量所占用的字节数。 sizeof 运算符的参数必须是一个非托管类型的名称,或是一个限定为非托管类型的类型参数。 sizeof 运算符需要不安全的上下文。 但在 C# 程序中常见的数据类型会被计算为相应的常数值,并不需要“不安全”的上下文。

示例如下:

Console.WriteLine(sizeof(byte));        // 输出:1
Console.WriteLine(sizeof(short));       // 输出:2
Console.WriteLine(sizeof(ushort));      // 输出:2
Console.WriteLine(sizeof(int));         // 输出:4
Console.WriteLine(sizeof(uint));        // 输出:4
Console.WriteLine(sizeof(long));        // 输出:8
Console.WriteLine(sizeof(ulong));       // 输出:8
Console.WriteLine(sizeof(float));       // 输出:4
Console.WriteLine(sizeof(double));      // 输出:8
Console.WriteLine(sizeof(decimal));     // 输出:16

6.2,typeof 运算符:

typeof 运算符表示用于获取某个类型的 System.Type 实例。 typeof 运算符的实参必须是类型或类型形参的名称。 同时 typeof 运算符的参数不能是需要元数据注释的类型。

示例如下:

Console.WriteLine(typeof(StreamReader));    // 输出: System.IO.StreamReader 
//Console.WriteLine(typeof(dynamic));     // 报错:typeof 运算符不能用在xx类型上 

6.3,is 运算符

is 运算符表示检查表达式结果的运行时类型是否与给定类型兼容。同时 is 运算符还会对照某个模式测试表达式结果。 E is T 其中 E 是返回一个值的表达式,T 是类型或类型参数的名称。 E 不得为匿名方法或 Lambda 表达式。

示例如下:

public class Base { }

public class Derived : Base { }

public static class IsOperatorExample
{
    public static void Main()
    {
        object b = new Base();
        Console.WriteLine(b is Base);       // 输出: True
        Console.WriteLine(b is Derived);    // 输出: False

        object d = new Derived();
        Console.WriteLine(d is Base);       // 输出: True
        Console.WriteLine(d is Derived);    // 输出: True
    }
} 

6.4,as 运算符:

as 运算符表示将表达式结果显式转换为给定的引用或可以为 null 值的类型。 如果无法进行转换,则 as 运算符返回 null。 与强制转换表达式不同,as 运算符永远不会引发异常。同时 as 运算符仅考虑引用、可以为 null、装箱和取消装箱转换。 不能使用 as 运算符执行用户定义的转换。

示例如下:

IEnumerable<int> numbers = new[] { 10, 20, 30 };
IList<int> indexable = numbers as IList<int>;

if (indexable != null)
{
    Console.WriteLine(indexable[0] + indexable[indexable.Count - 1]);   // 输出:40
}

6.5,三元条件运算符:

条件运算符 ( ?: ) 也称为三元条件运算符,表示用于计算布尔表达式,并根据布尔表达式的计算结果为 true 还是 false 来返回两个表达式中的一个结果,条件运算符的语法总结为: condition ? consequent : alternative;condition 表达式的计算结果必须为 true 或 false。若 condition 的计算结果为 true,将计算 consequent,其结果成为运算结果。 若 condition 的计算结果为 false,将计算 alternative,其结果成为运算结果。 只会计算 consequent 或 alternative。

示例如下:

string GetWeatherDisplay(double tempInCelsius) 
    => tempInCelsius < 20.0 ? "Cold." : "Perfect!";
Console.WriteLine(GetWeatherDisplay(15));   // 输出: Cold.
Console.WriteLine(GetWeatherDisplay(27));   // 输出: Perfect! 

6.6,Null 合并操作符:

Null 合并操作符表示如果左操作数的值不为 null,则 null 合并运算符 ?? 返回该值;否则,它会计算右操作数并返回其结果。 如果左操作数的计算结果为非 null,则 ?? 运算符不会计算其右操作数;仅当左操作数的计算结果为 null 时,Null 合并赋值运算符 ??= 才会将其右操作数的值赋值给其左操作数。 如果左操作数的计算结果为非 null,则 ??= 运算符不会计算其右操作数。

示例如下:

List<int> numbers = null;
int? a = null;
Console.WriteLine((numbers is null));   // 预期: true
                                                
(numbers ??= new List<int>()).Add(5);   // 如果numbers为空,则初始化它。然后,把数字加5

Console.WriteLine(string.Join(" ", numbers));   // 输出: 5
Console.WriteLine((numbers is null));   // 预期: false 
Console.WriteLine((a is null));     // 预期: true
Console.WriteLine((a ?? 3));        // 预期: 3 因为a仍然是空的
                                    // 如果a为空,则将0赋给a并将a添加到列表中
numbers.Add(a ??= 0);
Console.WriteLine((a is null));     // 预期: false 
Console.WriteLine(string.Join(" ", numbers)); // 输出: 5 0
Console.WriteLine(a);       // 输出: 0  

6.7,Null 条件运算符:

Null 条件运算符 ?. 和 ?[] 表示仅当操作数的计算结果为非 NULL 时,NULL 条件运算符才对其操作数应用成员访问 ?. 或元素访问 ?[] 操作;否则,它会返回 null。 即:

  • 如果 a 的计算结果为 null,则 a?.x 或 a?[x] 的结果为 null。
  • 如果 a 的计算结果为非 null,则 a?.x 或 a?[x] 的结果将分别与 a.x 或 a[x] 的结果相同。

同时 Null 条件运算符采用最小化求职策略。 也就是说如果条件成员或元素访问运算链中的一个运算返回 null,则链的其余部分不会执行。

示例如下:

using System; 

public class Program
{
    static double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
    {
        return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
    }

    static void Main(string[] args)
    {
        var sum1 = SumNumbers(null, 0);
        Console.WriteLine(sum1);    // 输出: NaN

        var numberSets = new List<double[]>
        {
             new[] { 1.0, 2.0, 3.0 },
             null
        };

        var sum2 = SumNumbers(numberSets, 0);
        Console.WriteLine(sum2);            // 输出: 6

        var sum3 = SumNumbers(numberSets, 1);
        Console.WriteLine(sum3);          // 输出: NaN 
    }

} 

7,运算符的优先级

以下表展示了 C# 中运算符的优先级:

类别或名称 运算符
主要 x.y、f(x)、a[i]、x?.y、x?[y]、x++、x--、x!、new、typeof、checked、unchecked、default、nameof、delegate、sizeof、stackalloc、x->y
一元 +x、-x、x、~x、++x、--x、^x、(T)x、await、&&x、*x、true 和 false
范围 x..y
switch 和 with 表达式 switch、with
乘法 x * y、x / y、x % y
加法 x + y、x – y
Shift x << y、x >> y
关系和类型测试 x < y、x > y、x <= y、x >= y、is、as
相等 x == y、x != y
布尔逻辑 AND 或按位逻辑 AND x & y
布尔逻辑 XOR 或按位逻辑 XOR x ^ y
布尔逻辑 OR 或按位逻辑 OR x \ y
条件 "与" x && y
条件"或" x \ \ y
Null 合并运算符 x ?? y
条件运算符 c ? t : f
赋值和 lambda 声明 x = y、x += y、x -= y、x *= y、x /= y、x %= y、x &= y、x \ = y、x ^= y、x <<= y、x >>= y、x??= y、=>

7.1,运算符优先级:

运算符优先级表示在包含多个运算符的表达式中,先按优先级较高的运算符计算,再按优先级较低的运算符计算。以下表按最高优先级到最低优先级的顺序列出 C# 运算符, 其中每行中运算符的优先级相同。

示例如下:

var a = 2 + 2 * 2;
Console.WriteLine(a); // 输出:6 

var b = (2 + 2) * 2;
Console.WriteLine(b); // 输出:8
  • 在包含多个运算符的表达式中,先按优先级较高的运算符计算,再按优先级较低的运算符计算。
  • 在此示例中,首先执行乘法,因为其优先级高于加法,使用括号更改运算符优先级所施加的计算顺序。

8,运算符重载

以下表展示了 C# 中可以重载的运算符:

运算符 描述
+x, -x, !x, ~x, ++, --, true, false true和 false 运算符必须一起重载。
x + y, x - y, x * y, x / y, x % y, x & y, x \ y, x ^ y, x << y, x >> y, x >>> y -
x == y, x != y, x < y, x > y, x <= y, x >= y 必须按如下方式成对重载: == 和 !=、 < 、 > <= 和 >=。

以下表展示了 C# 中不可重载的运算符:

运算符 替代方法
x && y, x \ \ y 重载 true 和 false 运算符以及 & 或 \ 运算符。
a[i], a?[i] 定义索引器。
(T)x 定义可由强制转换表达式执行的自定义类型转换。
+=, -=, *=, /=, %=, &=,\ =, ^=, <<=, >>=, >>>= 重载相应的二元运算符。 例如,重载二元 + 运算符时, += 将隐式重载。
^x, x = y, x.y, x?.y, c ? t : f, x ?? y, ??= y,x..y, x->y, =>, f(x), as, await, checked,unchecked, default, delegate, is, nameof,new,sizeof, stackalloc, switch, typeof, with 无。

8.1,运算符重载的实现:

运算符重载表示用户定义的类型可重载预定义的 C# 运算符。 也就是表示当一个或两个操作数都是某类型时,此类型可提供操作的自定义实现。运算符重载使用 operator 关键字来声明运算符, 运算符声明必须符合以下规则:

  • 同时包含 public 和 static 修饰符。
  • 一元运算符有一个输入参数。 二元运算符有两个输入参数。 在每种情况下,都至少有一个参数必须具有类型 T 或 T?,其中 T 是包含运算符声明的类型。

同时在 C# 程序并不是所有运算符都可以被重载,上面的两个表就分别介绍了 C# 程序中支持的可重载运算符和不可重载运算符。

示例如下:

// 定义了一个表示有理数的简单结构,该结构会重载一些算术运算符。
public readonly struct Fraction
{
    private readonly int num;
    private readonly int den;

    // 构造函数 
    public Fraction(int numerator, int denominator)
    {
        if (denominator == 0)
        {
            throw new ArgumentException("Denominator cannot be zero.", nameof(denominator)); 
        }

        num = numerator;
        den = denominator;
    }

    // 运算符重载部分 
    public static Fraction operator + (Fraction a) => a;
    public static Fraction operator - (Fraction a) => new Fraction(-a.num,
   a.den);

    public static Fraction operator + (Fraction a, Fraction b)
        => new Fraction(a.num * b.den + b.num * a.den, a.den * b.den);

    public static Fraction operator -(Fraction a, Fraction b)
        => a + (-b);

    public static Fraction operator *(Fraction a, Fraction b)
        => new Fraction(a.num * b.num, a.den * b.den);

    public static Fraction operator /(Fraction a, Fraction b)
    {
        if (b.num == 0)
        {
            throw new DivideByZeroException();
        }
        return new Fraction(a.num * b.den, a.den * b.num);
    }

    public override string ToString() => $"{num} / {den}";
}

public static class OperatorOverloading
{
    public static void Main()
    {
        var a = new Fraction(5, 4);
        var b = new Fraction(1, 2);

        Console.WriteLine(-a);          // 输出: -5 / 4
        Console.WriteLine(a + b);       // 输出: 14 / 8
        Console.WriteLine(a - b);       // 输出: 6 / 8
        Console.WriteLine(a * b);       // 输出: 5 / 8
        Console.WriteLine(a / b);       // 输出: 10 / 4
    }
}

结语

:heavy_check_mark: 以上就是 C# 运算符的总结,希望能够对大家有所帮助。望大家多多支持,你们的支持就是笔者创作最大的动力!
目录
相关文章
|
22天前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
31 3
|
21天前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
37 1
|
20天前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
11 0
|
1月前
|
C# 开发者
【捞底干货】C#中equals和==运算符的区别
【捞底干货】C#中equals和==运算符的区别
28 1
|
5月前
|
C# 数据库
C#中的空合并运算符与空合并赋值运算符:简化空值处理
C#中的空合并运算符与空合并赋值运算符:简化空值处理
|
6月前
|
开发框架 .NET 程序员
C#三元运算符使用技巧
C#三元运算符使用技巧
54 0
|
6月前
|
C# 数据安全/隐私保护
C#运算符
C#运算符
34 0
|
6月前
|
C#
C# 运算符详解:包含算术、赋值、比较、逻辑运算符及 Math 类应用
运算符用于对变量和值执行操作。在C#中,有多种运算符可用,包括算术运算符、关系运算符、逻辑运算符等。
78 1
|
6月前
|
C# 图形学
【Unity 3D】C#控制语句break、continue及算数运算符和逻辑运算符的讲解(附测试代码)
【Unity 3D】C#控制语句break、continue及算数运算符和逻辑运算符的讲解(附测试代码)
62 1
|
6月前
|
存储 C#
C#入门开发(Hello World,运算符)
C#入门开发(Hello World,运算符)
53 0