在本文中,我们介绍了C#运算符。
表达式由操作数和运算符构成。表达式的运算符指示将哪些操作应用于操作数。表达式中运算符的计算顺序由运算符的优先级和结合性决定。
运算符是一个特殊的符号,表示执行了某个过程。编程语言中的运算符取自数学。程序员与数据打交道。运算符用于处理数据。操作数是运算符的输入(参数)之一。
C#运算符列表
下表显示了C#语言中使用的一组运算符。
类别 | 符号 |
---|---|
符号运算符 | +- |
算术 | +-*/% |
逻辑(布尔和按位) | &|^!~&&||truefalse |
字符串拼接 | + |
自增、自减 | ++-- |
Shift | <> |
关系 | ==!== |
赋值 | =+=-=*=/=%=&=|=^=??=<>= |
会员权限 | 。?. |
索引 | []?[] |
Cast |
|
三元 | ?: |
委托拼接和移除 | +- |
对象创建 | new |
类型信息 | asissizeoftypeof |
溢出异常控制 | checkedunchecked |
Indirectionandaddress | *->[]& |
Lambda | => |
一个运算符通常有一个或两个操作数。那些只使用一个操作数的运算符称为一元运算符。那些使用两个操作数的运算符称为二元运算符。还有一个三元运算符?:,它使用三个操作数。
某些运算符可能会在不同的上下文中使用。例如+运算符。从上表我们可以看出它在不同的情况下使用。它添加数字,连接字符串或委托;表示数字的符号。我们说运算符过载。
C#一元运算符
C#一元运算符包括:+、-、++、--、强制转换运算符()和取反!。
C#符号运算符
有两个符号运算符:+
和-
。它们用于指示或更改值的符号。
Console.WriteLine(2); Console.WriteLine(+2); Console.WriteLine(-2);
+
和-
符号表示值的符号。加号可以用来表示我们有一个正数。它可以被省略,而且大部分都是这样做的。
int a = 1; Console.WriteLine(-a); Console.WriteLine(-(-a));
减号改变值的符号。
$ dotnet run -1 1
C#递增和递减运算符
将一个值递增或递减一个是编程中的常见任务。C#有两个方便的运算符:++
和--
。
x++; x = x + 1; ... y--; y = y - 1;
以上两对表达式作用相同。
int x = 6; x++; x++; Console.WriteLine(x); x--; Console.WriteLine(x);
在上面的例子中,我们演示了这两个运算符的用法。
int x = 6; x++; x++;
我们将x
变量初始化为6。然后我们将x
递增两次。现在变量等于8。
x--;
我们使用减量运算符。现在变量等于7。
$ dotnet run 8 7
C#显式转换运算符
显式转换运算符()可用于将一种类型转换为另一种类型。请注意,此运算符仅适用于某些类型。
float val = 3.2f; int num = (int) val; Console.WriteLine(num);
在示例中,我们显式地将float
类型转换为int
。
否定运算符
否定运算符(!)反转其操作数的含义。
var isValid = false; if (!isValid) { Console.WriteLine("The option is not valid"); }
在示例中,我们构建了一个否定条件:如果表达式的逆表达式有效,则执行该条件。
C#赋值运算符
赋值运算符=
为变量赋值。变量是值的占位符。在数学中,=
运算符具有不同的含义。在等式中,=
运算符是一个等式运算符。等式左边等于右边。
int x = 1;
这里我们为x
变量分配一个数字。
x = x + 1;
前面的表达式在数学上没有意义。但它在编程中是合法的。该表达式将1添加到x
变量。右边等于2,2赋值给x
。
3 = x;
此代码示例导致语法错误。我们不能为文字赋值。
C#连接字符串
+运算符也用于连接字符串。
Console.WriteLine("Return " + "of " + "the king.");
我们使用字符串连接运算符将三个字符串连接在一起。
$ dotnet run Return of the king.
C#算术运算符
下表是C#中的算术运算符。
符号 | 名称 |
---|---|
+ |
加法 |
- |
减法 |
* |
乘法 |
/ | 除法 |
% |
剩余 |
以下示例显示算术运算。
int a = 10; int b = 11; int c = 12; int add = a + b + c; int sb = c - a; int mult = a * b; int div = c / 3; int rem = c % a; Console.WriteLine(add); Console.WriteLine(sb); Console.WriteLine(mult); Console.WriteLine(div); Console.WriteLine(rem);
在前面的示例中,我们使用了加法、减法、乘法、除法和取余运算。这在数学中都很熟悉。
int rem = c % a;
%
运算符称为余数或取模运算符。它计算一个数除以另一个数的余数。例如,9%4
,9模4为1,因为4进9两次,余数为1。
$ dotnet run 33 2 110 4 2
接下来我们展示整数除法和浮点除法的区别。
int c = 5 / 2; Console.WriteLine(c); double d = 5 / 2.0; Console.WriteLine(d);
在前面的示例中,我们将两个数字相除。
int c = 5 / 2; Console.WriteLine(c);
在这段代码中,我们完成了整数除法。除法运算的返回值是一个整数。当我们除以两个整数时,结果是一个整数。
double d = 5 / 2.0; Console.WriteLine(d);
如果其中一个值是double或float,我们执行浮点除法。在我们的例子中,第二个操作数是一个双精度数,所以结果是一个双精度数。
$ dotnet run 2 2.5
C#布尔运算符
在C#中,我们有三个逻辑运算符。bool
关键字用于声明布尔值。
符号 | 名称 |
---|---|
&& |
逻辑与 |
|| |
逻辑或 |
! |
否定 |
布尔运算符也称为逻辑运算符。
int x = 3; int y = 8; Console.WriteLine(x == y); Console.WriteLine(y > x); if (y > x) { Console.WriteLine("y is greater than x"); }
许多表达式会产生一个布尔值。布尔值用于条件语句。
Console.WriteLine(x == y); Console.WriteLine(y > x);
关系运算符总是产生一个布尔值。这两条线打印出false和true。
if (y > x) { Console.WriteLine("y is greater than x"); }
if
语句的主体只有在满足括号内的条件时才会执行。y>x
返回true,因此消息“yisgreaterthanx”被打印到终端。
true
和false
关键字表示C#中的布尔值。
bool a = true && true; bool b = true && false; bool c = false && true; bool d = false && false; Console.WriteLine(a); Console.WriteLine(b); Console.WriteLine(c); Console.WriteLine(d);
示例显示了逻辑与运算符。仅当两个操作数都为真时,它才计算为真。
$ dotnet run True False False False
只有一个表达式的结果为True
。
逻辑或||
运算符的计算结果为真,如果其中一个操作数为真。
bool a = true || true; bool b = true || false; bool c = false || true; bool d = false || false; Console.WriteLine(a); Console.WriteLine(b); Console.WriteLine(c); Console.WriteLine(d);
如果运算符的其中一侧为真,则运算结果为真。
$ dotnet run True True True False
四个表达式中的三个结果为真。
否定运算符!
使true为false,false为true。
Console.WriteLine(!true); Console.WriteLine(!false); Console.WriteLine(!(4 < 3));
该示例显示了否定运算符的作用。
$ dotnet run False True True
||
和&&
运算符是短路评估的。短路求值表示仅当第一个参数不足以确定表达式的值时才对第二个参数求值:当逻辑和的第一个参数求值为假时,整体值必须为假;当逻辑或的第一个参数评估为真时,整体值必须为真。短路评估主要用于提高性能。
一个例子可能会更清楚地说明这一点。
Console.WriteLine("Short circuit"); if (One() && Two()) { Console.WriteLine("Pass"); } Console.WriteLine("#############"); if (Two() || One()) { Console.WriteLine("Pass"); } bool One() { Console.WriteLine("Inside one"); return false; } bool Two() { Console.WriteLine("Inside two"); return true; }
我们在示例中有两个方法。它们用作布尔表达式中的操作数。
if (One() && Two()) { Console.WriteLine("Pass"); }
One
方法返回false
。短路&&不评估第二种方法。没有必要。一旦操作数为false
,逻辑结论的结果始终为false
。只有“Insideone”才会打印到控制台。
Console.WriteLine("#############"); if (Two() || One()) { Console.WriteLine("Pass"); }
在第二种情况下,我们使用||
运算符并使用Two
方法作为第一个操作数。在这种情况下,“Insidetwo”和“Pass”字符串会打印到终端。再次没有必要计算第二个操作数,因为一旦第一个操作数计算为true
,逻辑or总是true
。
$ dotnet run Short circuit Inside one ############# Inside two Pass
C#关系运算符
关系运算符用于比较值。这些运算符总是产生布尔值。
符号 | 含义 |
---|---|
< |
小于 |
<= |
小于等于 |
> |
大于 |
>= |
大于或等于 |
== |
等于 |
code>!= | 不等于 |
关系运算符也称为比较运算符。
Console.WriteLine(3 < 4); Console.WriteLine(3 == 4); Console.WriteLine(4 >= 3); Console.WriteLine(4 != 3);
在代码示例中,我们有四个表达式。这些表达式比较整数值。每个表达式的结果不是真就是假。在C#中,我们使用==
来比较数字。某些语言(如Ada、VisualBasic或Pascal)使用=
来比较数字。
C#按位运算符
小数对人类来说很自然。二进制数是计算机固有的。二进制、八进制、十进制或十六进制符号只是相同数字的表示法。按位运算符处理二进制数的位。按位运算符很少用于C#等高级语言。
符号 | 含义 |
---|---|
~ |
按位取反 |
^ |
按位异或 |
& |
位与 |
| |
位与 |
按位取反运算符将每个1更改为0,将0更改为1。
Console.WriteLine(~ 7); // prints -8 Console.WriteLine(~ -8); // prints 7
运算符将数字7的所有位取反。其中一位还确定数字是否为负数。如果我们再次取反所有位,我们将再次得到数字7。
按位与运算符在两个数字之间执行逐位比较。仅当操作数中的对应位均为1时,位位置的结果才为1。
00110 & 00011 = 00010
第一个数是6的二进制数,第二个是3,结果是2。
Console.WriteLine(6 & 3); // prints 2 Console.WriteLine(3 & 6); // prints 2
按位或运算符在两个数字之间执行逐位比较。如果操作数中相应的位为1,则位位置的结果为1。
00110 | 00011 = 00111
结果是00110
或十进制的7。
Console.WriteLine(6 | 3); // prints 7 Console.WriteLine(3 | 6); // prints 7
按位异或运算符在两个数字之间执行逐位比较。如果操作数中对应位中的一个或另一个(但不是两个),则位位置的结果为1为1。
00110 ^ 00011 = 00101
结果为00101
或十进制数5。
Console.WriteLine(6 ^ 3); // prints 5 Console.WriteLine(3 ^ 6); // prints 5
C#复合赋值运算符
复合赋值运算符由两个运算符组成,它们是简写运算符。
a = a + 3; a += 3;
+=
复合运算符就是这些简写运算符之一。以上两个表达式是相等的。值3被添加到a变量。
其他复合运算符是:
-= *= /= %= &= |= <<= >>=
int a = 1; a = a + 1; Console.WriteLine(a); a += 5; Console.WriteLine(a); a *= 3; Console.WriteLine(a);
在示例中,我们使用了两个复合运算符。
int a = 1; a = a + 1;
a
变量初始化为1。使用非速记符号将1添加到变量。
a += 5;
使用+=
复合运算符,我们将5添加到a
变量。该语句等于a=a+5;
。
a *= 3;
使用*=
运算符,将a
乘以3。语句等于a=a*3;
。
$ dotnet run 2 7 21
C#新运算符
new
运算符用于创建对象和调用构造函数。
var b = new Being(); Console.WriteLine(b); var vals = new int[] { 1, 2, 3, 4, 5 }; Console.WriteLine(string.Join(" ", vals)); class Being { public Being() { Console.WriteLine("Being created"); } }
在示例中,我们使用new
运算符创建了一个新的自定义对象和一个整数数组。
public Being() { Console.WriteLine("Being created"); }
这是一个构造函数。它在创建对象时被调用。
$ dotnet run Being created Being 1 2 3 4 5
C#访问运算符
访问运算符[]
用于数组、索引器和属性。
var vals = new int[] { 2, 4, 6, 8, 10 }; Console.WriteLine(vals[0]); var domains = new Dictionary() { { "de", "Germany" }, { "sk", "Slovakia" }, { "ru", "Russia" } }; Console.WriteLine(domains["de"]); oldMethod(); [Obsolete("Don't use OldMethod, use NewMethod instead", false)] void oldMethod() { Console.WriteLine("oldMethod()"); } void newMethod() { Console.WriteLine("newMethod()"); }
在示例中,我们使用[]
运算符获取数组的元素、字典对的值,并激活内置属性。
var vals = new int[] { 2, 4, 6, 8, 10 }; Console.WriteLine(vals[0]);
我们定义了一个整数数组。我们使用vals[0]
获取第一个元素。
var domains = new Dictionary<string, string>() { { "de", "Germany" }, { "sk", "Slovakia" }, { "ru", "Russia" } }; Console.WriteLine(domains["de"]);
创建了一个字典。使用domains["de"]
,我们获得具有"de"
键的对的值。
[Obsolete("Don't use OldMethod, use NewMethod instead", false)] public static void oldMethod() { Console.WriteLine("oldMethod()"); }
我们激活内置的Obsolete
属性。该属性发出警告。
当我们运行该程序时,它会产生警告:warningCS0618:'oldMethod()'isobsolete:'Don'tuseOldMethod,useNewMethodinstead'
。
来自结束运算符的C#索引^
结束运算符^的索引表示从序列末尾开始的元素位置。例如,^1
指向序列的最后一个元素,^n
指向偏移量为length-n
的元素。
int[] vals = { 1, 2, 3, 4, 5 }; Console.WriteLine(vals[^1]); Console.WriteLine(vals[^2]); var word = "gray falcon"; Console.WriteLine(word[^1]);
在示例中,我们将运算符应用于数组和字符串。
int[] vals = { 1, 2, 3, 4, 5 }; Console.WriteLine(vals[^1]); Console.WriteLine(vals[^2]);
我们打印数组的最后一个元素。
var word = "gray falcon"; Console.WriteLine(word[^1]);
我们打印单词的最后一个字母。
$ dotnet run 5 4 n
C#范围运算符..
..
运算符指定索引范围的开始和结束作为其操作数。左边的操作数是一个范围的开始。右边的操作数是范围的排他性结束。
x.. is equivalent to x..^0 ..y is equivalent to 0..y .. is equivalent to 0..^0
可以省略..
运算符的操作数以获得开放式范围。
int[] vals = { 1, 2, 3, 4, 5, 6, 7 }; var slice1 = vals[1..4]; Console.WriteLine("[{0}]", string.Join(", ", slice1)); var slice2 = vals[..^0]; Console.WriteLine("[{0}]", string.Join(", ", slice2));
在示例中,我们使用..
运算符来获取数组切片。
var range1 = vals[1..4]; Console.WriteLine("[{0}]", string.Join(", ", range1));
我们创建一个从索引1到索引4的数组切片;不包括最后一个索引4。
var slice2 = vals[..^0]; Console.WriteLine("[{0}]", string.Join(", ", slice2));
这里我们基本上创建了数组的副本。
$ dotnet run [2, 3, 4] [1, 2, 3, 4, 5, 6, 7]
C#类型信息
现在我们关注与类型一起工作的运算符。
sizeof
运算符用于获取值类型的sizein字节。typeof
用于获取类型的System.Type
对象。
Console.WriteLine(sizeof(int)); Console.WriteLine(sizeof(float)); Console.WriteLine(sizeof(Int32)); Console.WriteLine(typeof(int)); Console.WriteLine(typeof(float));
我们使用sizeof
和typeof
运算符。
$ dotnet run 4 4 4 System.Int32 System.Single
我们可以看到int
类型是System.Int32
的别名,float
是System的别名.单
类型。
is
运算符检查对象是否与给定类型兼容。
Base _base = new Base(); Derived derived = new Derived(); Console.WriteLine(_base is Base); Console.WriteLine(_base is Object); Console.WriteLine(derived is Base); Console.WriteLine(_base is Derived); class Base { } class Derived : Base { }
我们从用户定义的类型创建两个对象。
class Base {} class Derived : Base {}
我们有一个Base
和一个Derived
类。Derived
类继承自Base
类。
Console.WriteLine(_base is Base); Console.WriteLine(_base is Object);
Base
等于Base
因此第一行打印为True。Base
也与Object
类型兼容。这是因为每个类都继承自所有类的母体-Object
类。
Console.WriteLine(derived is Base); Console.WriteLine(_base is Derived);
派生对象与Base
类兼容,因为它显式继承自Base
类。另一方面,_base
对象与Derived
类无关。
$ dotnet run True True True False
as
运算符用于执行兼容引用类型之间的转换。当无法转换时,运算符返回null。与引发异常的转换操作不同。
object[] objects = new object[6]; objects[0] = new Base(); objects[1] = new Derived(); objects[2] = "ZetCode"; objects[3] = 12; objects[4] = 1.4; objects[5] = null; for (int i = 0; i < objects.Length; i++) { string s = objects[i] as string; Console.Write("{0}:", i); if (s != null) { Console.WriteLine(s); } else { Console.WriteLine("not a string"); } } class Base { } class Derived : Base { }
在上面的示例中,我们使用as
运算符来执行转换。
string s = objects[i] as string;
我们尝试将各种类型转换为字符串类型。但只有一次转换才有效。
$ dotnet run 0:not a string 1:not a string 2:ZetCode 3:not a string 4:not a string 5:not a string
C#运算符优先级
运算符优先级告诉我们首先评估哪些运算符。优先级级别对于避免表达式中的歧义是必要的。
以下表达式的结果是28还是40?
3 + 5 * 5
与数学一样,乘法运算符的优先级高于加法运算符。所以结果是28。
(3 + 5) * 5
要改变求值顺序,我们可以使用括号。括号内的表达式总是先求值。
下表显示了按优先级排序的常见C#运算符(最高优先级在前):
运算符 | 类别 | 关联性 |
---|---|---|
主要 | x.yx?.y,x?[y]f(x)a[x]x++x--newtypeofdefaultcheckedunchecked |
左 |
一元 | +-!~++x--x(T)x |
左移 |
乘法 | */% |
左 |
加法 | +- |
向左 |
Shift | <> |
向左 |
相等 | ==!= |
右 |
逻辑与 | & |
左 |
逻辑异或 | ^ |
左 |
逻辑或 | | |
左 |
条件与 | && |
左 |
条件或 | || |
左 |
空合并 | ?? |
左 |
三元 | ?: |
对 |
赋值 | =*=/=%=+=-=<>=&=^=|=??==> |
右 |
表中同一行的运算符具有相同的优先级。
Console.WriteLine(3 + 5 * 5); Console.WriteLine((3 + 5) * 5); Console.WriteLine(! true | true); Console.WriteLine(! (true | true));
在这个代码示例中,我们展示了几个表达式。每个表达式的结果取决于优先级。
Console.WriteLine(3 + 5 * 5);
此行打印28。乘法运算符的优先级高于加法运算符。首先计算5*5
的乘积,然后加上3。
Console.WriteLine(! true | true);
在这种情况下,否定运算符具有更高的优先级。首先,第一个真值被否定为假,然后|
运算符将假和真结合起来,最后得到真。
$ dotnet run 28 40 True False
C#关联规则
有时优先级不能令人满意地确定表达式的结果。还有一个规则叫做关联性。运算符的结合性决定了具有相同优先级的运算符的求值顺序。
9 / 3 * 3
这个表达式的结果是9还是1?乘法、删除和模运算符是从左到右关联的。因此表达式的计算方式如下:(9/3)*3
结果为9。
算术运算符、布尔运算符、关系运算符和按位运算符都是从左到右关联的。
另一方面,赋值运算符是右关联的。
int a, b, c, d; a = b = c = d = 0; Console.WriteLine("{0} {1} {2} {3}", a, b, c, d); int j = 0; j *= 3 + 1; Console.WriteLine(j);
在示例中,我们有两种情况,其中关联性规则决定了表达式。
int a, b, c, d; a = b = c = d = 0;
赋值运算符是从右到左关联的。如果是从左到右的关联,则前面的表达式将无法实现。
int j = 0; j *= 3 + 1;
复合赋值运算符是从右到左关联的。我们可能期望结果是1,但实际结果是0。因为关联性。首先计算右侧的表达式,然后应用复合赋值运算符。
$ dotnet run 0 0 0 0 0
C#空条件运算符
空条件运算符仅将成员访问?.
或元素访问?[]
操作应用于其操作数如果该操作数的计算结果为非空。如果操作数的计算结果为null
,则应用该运算符的结果为null。
var users = new List<User>() { new User("John Doe", "gardener"), new User(null, null), new User("Lucia Newton", "teacher") }; users.ForEach(user => Console.WriteLine(user.Name?.ToUpper())); record User(string? Name, string? Occupation);
在示例中,我们有一个包含两个成员的User
类:Name
和Occupation
。我们在?.
运算符的帮助下访问对象的name
成员。
var users = new List<User>() { new User("John Doe", "gardener"), new User(null, null), new User("Lucia Newton", "teacher") };
我们有一个用户列表。其中之一用空值初始化。
users.ForEach(user => Console.WriteLine(user.Name?.ToUpper()));
我们使用?.
访问Name
成员并调用ToUpper
方法。?.
通过不对null
值调用ToUpper
来防止System.NullReferenceException
。
$ dotnet run JOHN DOE LUCIA NEWTON
在下面的示例中,我们使用?[]
运算符。该运算符允许将null
值放入集合中。
int?[] vals = { 1, 2, 3, null, 4, 5 }; int i = 0; while (i < vals.Length) { Console.WriteLine(vals[i]?.GetType()); i++; }
在这个例子中,我们在数组中有一个null
值。我们通过对数组元素应用?.
运算符来防止System.NullReferenceException
。
C#空合并运算符
空合并运算符??
用于为nullable
类型定义默认值。如果它不为空,它返回左边的操作数;否则返回正确的操作数。当我们使用数据库时,我们经常处理缺失值。这些值作为空值出现在程序中。该运算符是处理此类情况的便捷方式。
int? x = null; int? y = null; int z = x ?? y ?? -1; Console.WriteLine(z);
空合并运算符的示例程序。
int? x = null; int? y = null;
两个可空的int
类型初始化为null
。int?
是Nullable
.它允许将空值分配给int
类型。
int z = x ?? y ?? -1;
我们想给z
变量赋值。但它不能为null
。这是我们的要求。为此,我们可以轻松地使用空合并运算符。如果x
和y
变量都为空,我们将-1分配给z
。
$ dotnet run -1
C#空合并赋值运算符
空合并赋值运算符??=
仅当左侧操作数赋值为null
时,才将其右侧操作数的值分配给其左侧操作数。如果左侧操作数的计算结果为非空,则??=
运算符不会计算其右侧操作数。它在C#8.0及更高版本中可用。
List<int> vals = null; vals ??= new List<int>() {1, 2, 3, 4, 5, 6}; vals.Add(7); vals.Add(8); vals.Add(9); Console.WriteLine(string.Join(", ", vals)); vals ??= new List<int>() {1, 2, 3, 4, 5, 6}; Console.WriteLine(string.Join(", ", vals));
在示例中,我们对整数值列表使用空合并赋值运算符。
List<int> vals = null;
首先,列表被分配给null
。
vals ??= new List<int>() {1, 2, 3, 4, 5, 6};
我们使用??=
为变量分配一个新的列表对象。由于它是null
,因此分配了列表。
vals.Add(7); vals.Add(8); vals.Add(9); Console.WriteLine(string.Join(", ", vals));
我们向列表中添加一些值并打印其内容。
vals ??= new List<int>() {1, 2, 3, 4, 5, 6};
我们尝试为变量分配一个新的列表对象。由于变量不再是null
,因此不会分配列表。
$ dotnet run 1, 2, 3, 4, 5, 6, 7, 8, 9 1, 2, 3, 4, 5, 6, 7, 8, 9
C#三元运算符
三元运算符?:
是一个条件运算符。对于我们想要根据条件表达式选取两个值之一的情况,这是一个方便的运算符。
cond-exp ? exp1 : exp2
如果cond-exp为真,则计算exp1并返回结果。如果cond-exp为假,则计算exp2并返回其结果。
int age = 31; bool adult = age >= 18 ? true : false; Console.WriteLine("Adult: {0}", adult);
在大多数国家/地区,成年取决于您的年龄。如果您的年龄超过特定年龄,您就是成年人。这是三元运算符的情况。
bool adult = age >= 18 ? true : false;
首先对赋值运算符右边的表达式进行求值。三元运算符的第一阶段是条件表达式求值。所以如果年龄大于等于18,?字符被返回。如果不是,则返回
:
字符后的值。然后将返回值分配给成人变量。
$ dotnet run Adult: True
一个31岁的人是成年人。
C#Lambda运算符
=>
标记称为lambda运算符。它是一个取自函数式语言的运算符。这个运算符可以使代码更短更清晰。另一方面,理解语法可能很棘手。特别是如果程序员以前从未使用过函数式语言。
只要我们可以使用委托,我们也可以使用lambda表达式。lambda表达式的定义是:lambda表达式是一个可以包含表达式和语句的匿名函数。左侧是一组数据,右侧是表达式或语句块。这些语句应用于数据的每一项。
在lambda表达式中我们没有return关键字。最后一条语句会自动返回。而且我们不需要为我们的参数指定类型。编译器会猜测正确的参数类型。这称为类型推断。
var list = new List<int>() { 3, 2, 1, 8, 6, 4, 7, 9, 5 }; var subList = list.FindAll(val => val > 3); foreach (int i in subList) { Console.WriteLine(i); }
我们有一个整数列表。我们打印所有大于3的数字。
var list = new List<int>() { 3, 2, 1, 8, 6, 4, 7, 9, 5 };
我们有一个通用的整数列表。
var subList = list.FindAll(val => val > 3);
这里我们使用lambda运算符。FindAll
方法将谓词作为参数。谓词是一种特殊类型的委托,它返回一个布尔值。谓词适用于列表的所有项目。val
是未指定类型的输入参数。我们可以明确指定类型,但这不是必需的。
编译器需要一个int
类型。val
是列表中的当前输入值。比较它是否大于3并返回布尔值true或false。最后,FindAll
将返回所有满足条件的值。它们被分配给子列表集合。
foreach (int i in subList) { Console.WriteLine(i); }
子列表集合的项目被打印到终端。
$ dotnet run 8 6 4 7 9 5
大于3的整数列表中的值。
var nums = new List<int>() { 3, 2, 1, 8, 6, 4, 7, 9, 5 }; var nums2 = nums.FindAll( delegate(int i) { return i > 3; } ); foreach (int i in nums2) { Console.WriteLine(i); }
这是同一个例子。我们使用匿名委托而不是lambda表达式。
C#计算素数
我们要计算素数。
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 }; Console.Write("Prime numbers: "); foreach (int num in nums) { if (num == 1) continue; if (num == 2 || num == 3) { Console.Write(num + " "); continue; } int i = (int) Math.Sqrt(num); bool isPrime = true; while (i > 1) { if (num % i == 0) { isPrime = false; } i--; } if (isPrime) { Console.Write(num + " "); } } Console.Write('\n');
在上面的例子中,我们处理了许多不同的运算符。素数(或素数)是恰好有两个不同的自然数除数的自然数:1和它本身。我们拿起一个数字并将其除以数字,从1到拿起的数字。实际上,我们不必尝试所有较小的数字;我们可以除以所选数字的平方根。该公式将起作用。我们使用余数除法运算符。
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 };
我们根据这些数字计算素数。
if (num == 1) continue;
根据定义,1不是质数
if (num == 2 || num == 3) { Console.Write(num + " "); continue; }
我们跳过2和3的计算:它们是素数。注意相等和条件或运算符的用法。==
运算符的优先级高于||
运算符。因此我们不需要使用括号。
int i = (int) Math.Sqrt(num);
如果我们只尝试小于数字查询的平方根的数字,我们就可以了。数学证明,考虑到相关数字的平方根的值就足够了。
while (i > 1) { ... i--; }
这是一个while循环。i
是计算出的数字的平方根。我们使用递减运算符在每个循环周期将i减一。当i小于1时,我们终止循环。例如,我们有数字9。9的平方根是3,我们把9这个数除以3和2。
if (num % i == 0) { isPrime = false; }
这是算法的核心。如果余数除法运算符对任何i值返回0,则所讨论的数字不是质数。
在本文中,我们介绍了C#运算符。
列出所有C#教程。