C#教程5:操作算子(2)
十、C# 复合赋值运算符
复合赋值运算符由两个运算符组成。他们是速记运算符。
a = a + 3; a += 3;+= 复合运算符是这些速记运算符之一。上面两个表达式是相等的。值 3 被添加到 a 变量中。
其他复合运算符有:
-= *= /= %= &= |= <<= >>=Program.cs
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操作符
new 运算符用于创建对象和调用构造函数。
Program.cs
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# 访问运算符
访问运算符 [] 与数组、索引器和属性一起使用。
Program.cs
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()"); }我们激活了内置的过时属性。该属性发出警告。
当我们运行程序时,它会产生警告:warning CS0618: 'oldMethod()' is obsolete: 'Don't use OldMethod, use NewMethod instead'。
十三、C# 索引符号 ^
结束运算符 ^ 的索引表示从序列末尾开始的元素位置。例如,^1 指向序列的最后一个元素,^n 指向偏移长度为 n 的元素。
Program.cs
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.. 运算符的操作数可以省略以获得开放范围。
Program.cs
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 运算符用于获取值类型的大小(以字节为单位)。 typeof 用于获取类型的 System.Type 对象。
Program.cs
Console.WriteLine(sizeof(int)); Console.WriteLine(sizeof(float)); Console.WriteLine(sizeof(Int32));Console.WriteLine(typeof(int)); Console.WriteLine(typeof(float));We use the sizeof and typeof operators.
$ dotnet run 4 4 4 System.Int32我们可以看到 int 类型是 System.Int32 的别名,float 是 System.Single 类型的别名。
is 运算符检查对象是否与给定类型兼容。
Program.cs
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 类。派生类继承自基类。
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 对象与 Derived 类无关。
$ dotnet run True True True Falseas 运算符用于在兼容的引用类型之间执行转换。当无法进行转换时,运算符返回 null。与引发异常的强制转换操作不同。
Program.cs
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# 运算符(最高优先级在前)
Operator(s)CategoryAssociativityPrimary | x.y x?.y, x?[y] f(x) a[x] x++ x-- new typeof default checked unchecked | Left |
Unary | + - ! ~ ++x --x (T)x | Left |
Multiplicative | * / % | Left |
Additive | + - | Left |
Shift | << >> | Left |
Equality | == != | Right |
Logical AND | & | Left |
Logical XOR | ^ | Left |
Logical OR | | | Left |
Conditional AND | && | Left |
Conditional OR | || | Left |
Null Coalescing | ?? | Left |
Ternary | ?: | Right |
Assignment | = *= /= %= += -= <<= >>= &= ^= |= ??= => | Right |
表同一行上的运算符具有相同的优先级。
Program.cs
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);在这种情况下,否定运算符具有更高的优先级。首先,第一个真值被否定为假,然后 |运算符将 false 和 true 组合在一起,最终给出 true。
$ dotnet run 28 40 True False十七、C# 关联规则
有时,优先级不能令人满意地确定表达式的结果。还有另一条规则称为关联性。运算符的关联性决定了具有相同优先级的运算符的评估顺序。
9 / 3 * 3这个表达式的结果是 9 还是 1?乘法、删除和模运算符从左到右关联。所以表达式是这样计算的:(9 / 3) * 3,结果是 9。
算术、布尔、关系和位运算符都是从左到右关联的。
另一方面,赋值运算符是右关联的。
Program.cs
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 条件运算符才会将成员访问、?. 或元素访问、?[] 操作应用于其操作数。如果操作数的计算结果为 null,则应用运算符的结果为 null。
Program.cs
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);在示例中,我们有一个包含两个成员的用户类:姓名和职业。我们在 ? 的帮助下访问对象的名称成员。操作员。
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 DOELUCIA NEWTON在以下示例中,我们使用 ?[] 运算符。该运算符允许将空值放入集合中。
Program.cs
int?[] vals = { 1, 2, 3, null, 4, 5 };int i = 0;while (i < vals.Length) {Console.WriteLine(vals[i]?.GetType());i++; }在此示例中,我们在数组中有一个空值。我们通过应用 ? 来防止 System.NullReferenceException。数组元素上的运算符。
十九、C# 空合并运算符
空合并运算符??用于定义可空类型的默认值。如果它不为空,则返回左操作数;否则返回正确的操作数。当我们使用数据库时,我们经常处理缺失值。这些值作为程序的空值出现。此运算符是处理此类情况的便捷方式。
Program.cs
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> 的简写。它允许将 null 值分配给 int 类型。
int z = x ?? y ?? -1;我们想为 z 变量赋值。但它不能为空。这是我们的要求。我们可以很容易地为此使用空合并运算符。如果 x 和 y 变量都为空,我们将 -1 分配给 z。
$ dotnet run -1二十、C# 空合并赋值运算符
仅当左侧操作数的计算结果为 null 时,null 合并赋值运算符 ??= 才将其右侧操作数的值分配给其左侧操作数。如果左侧操作数的计算结果为非空,则??= 运算符不计算其右侧操作数。它在 C# 8.0 及更高版本中可用。
Program.cs
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};我们尝试为变量分配一个新的列表对象。由于变量不再为空,因此未分配列表。
$ 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 并返回其结果。
Program.cs
int age = 31;bool adult = age >= 18 ? true : false;Console.WriteLine("Adult: {0}", adult);在大多数国家,成年期取决于您的年龄。如果您超过某个年龄,您就是成年人。这是三元运算符的情况。
bool adult = age >= 18 ? true : false;首先评估赋值运算符右侧的表达式。三元运算符的第一阶段是条件表达式求值。因此,如果年龄大于或等于 18,则后面的值是?返回字符。如果不是,则返回 : 字符后面的值。然后将返回的值分配给成人变量。
$ dotnet run Adult: TrueA 31 years old person is adult.
二十二、C# Lambda操作符号
=> 标记称为 lambda 运算符。它是取自函数式语言的运算符。该运算符可以使代码更短更清晰。另一方面,理解语法可能很棘手。特别是如果程序员以前从未使用过函数式语言。
只要我们可以使用委托,我们也可以使用 lambda 表达式。 lambda 表达式的定义是:lambda 表达式是一个匿名函数,可以包含表达式和语句。左侧是一组数据,右侧是表达式或语句块。这些陈述适用于每一项数据。
在 lambda 表达式中,我们没有 return 关键字。最后一条语句会自动返回。而且我们不需要为我们的参数指定类型。编译器将猜测正确的参数类型。这称为类型推断。
Program.cs
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 的整数列表中的值。
Program.cs
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# 计算素数
我们要计算素数。
Program.cs
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;By definition, 1 is not a prime
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#教程5:操作算子(2)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 机器学习:论相关(二)
- 下一篇: 时间序列:等分布序列(Equidistr