C#学习之语句、表达式和运算符

语句

程序所执行的操作以“语句”表达。 常见操作包括声明变量、赋值、调用方法、循环访问集合,以及根据给定条件分支到一个或另一个代码块。 语句在程序中的执行顺序称为“控制流”或“执行流”。 根据程序对运行时所收到的输入的响应,在程序每次运行时控制流可能有所不同。

语句可以是以分号结尾的单行代码,或者是语句块中的一系列单行语句。 语句块括在括号 {} 中,并且可以包含嵌套块。 下面的代码演示两个单行语句示例和一个多行语句块:

C#
    static void Main()
    {
        // Declaration statement.
        int counter;

        // Assignment statement.
        counter = 1;

        // Error! This is an expression, not an expression statement.
        // counter + 1; 

        // Declaration statements with initializers are functionally
        // equivalent to  declaration statement followed by assignment statement:         
        int[] radii = { 15, 32, 108, 74, 9 }; // Declare and initialize an array.
        const double pi = 3.14159; // Declare and initialize  constant.          

        // foreach statement block that contains multiple statements.
        foreach (int radius in radii)
        {
            // Declaration statement with initializer.
            double circumference = pi * (2 * radius);

            // Expression statement (method invocation). A single-line
            // statement can span multiple text lines because line breaks
            // are treated as white space, which is ignored by the compiler.
            System.Console.WriteLine("Radius of circle #{0} is {1}. Circumference = {2:N2}",
                                    counter, radius, circumference);

            // Expression statement (postfix increment).
            counter++;

        } // End of foreach statement block
    } // End of Main method body.
} // End of SimpleStatements class.
/*
   Output:
    Radius of circle #1 = 15. Circumference = 94.25
    Radius of circle #2 = 32. Circumference = 201.06
    Radius of circle #3 = 108. Circumference = 678.58
    Radius of circle #4 = 74. Circumference = 464.96
    Radius of circle #5 = 9. Circumference = 56.55
*/

语句的类型

下面列出 C# 中的各种语句类型及其关联的关键字

声明语句
声明语句引入新的变量或常量。 变量声明可以选择为变量赋值。 在常量声明中必须赋值。

C#
// Variable declaration statements.
double area;
double radius = 2;

// Constant declaration statement.
const double pi = 3.14159;

表达式语句
用于计算值的表达式语句必须在变量中存储该值。

C#
// Expression statement (assignment).
area = 3.14 * (radius * radius);

// Error. Not  statement because no assignment:
//circ * 2;

// Expression statement (method invocation).
System.Console.WriteLine();

// Expression statement (new object creation).
System.Collections.Generic.List<string> strings =
    new System.Collections.Generic.List<string>();

选择语句
选择语句用于根据一个或多个指定条件分支到不同的代码段。

迭代语句
迭代语句用于遍历集合(如数组),或重复执行同一组语句直到满足指定的条件。

跳转语句
跳转语句将控制转移给另一代码段。

异常处理语句
异常处理语句用于从运行时发生的异常情况正常恢复。

检查和未检查
检查和未检查语句用于指定当将结果存储在变量中、但该变量过小而不能容纳结果值时,是否允许数值运算导致溢出。

如果标记与 异步 修饰符的方法,在方法可以使用 等待 运算符。 当控件移到在异步方法中的一个 await 表达式,控件回调用方,因此,在方法的进度挂起,直到等待任务完成。 当任务完成后,执行在方法可以恢复。

yield return 语句
迭代器对集合的自定义迭代,如列表或数组。 迭代器使用 将返回 语句返回每个元素一个节点。 当 yield return 语句时,代码的当前位置确保。 迭代器,当下次时,调用执行从该位置进行重新启动。

fixed 语句
Fixed 语句禁止垃圾回收器重定位可移动的变量。

lock 语句
lock 语句用于限制一次仅允许一个线程访问代码块。

标记语句
可以为语句指定一个标记,然后使用 goto 关键字跳转到该标记语句。

空语句
空语句只含一个分号。 空语句不执行任何操作,可以在需要语句但不需要执行任何操作的地方使用。 下面的示例演示空语句的两种用法:

C#
void ProcessMessages()
{
    while (ProcessMessage())
        ; // Statement needed here.
}

void F()
{
    //...
    if (done) goto exit;
//...
exit:
    ; // Statement needed here.
}

嵌入语句

一些语句(例如 do、while、for 和 foreach)后面始终跟有一条嵌入语句。 此嵌入语句可以是单个语句,也可以是语句块中括在括号 {} 内的多个语句。 甚至可以在括号 {} 内包含单行嵌入语句,如下面的示例所示:

C#
// Recommended style. Embedded statement in  block.
foreach (string s in System.IO.Directory.GetDirectories(
                        System.Environment.CurrentDirectory))
{
    System.Console.WriteLine(s);
}

// Not recommended.
foreach (string s in System.IO.Directory.GetDirectories(
                        System.Environment.CurrentDirectory))
    System.Console.WriteLine(s);

未括在括号 {} 内的嵌入语句不能作为声明语句或标记语句。 下面的示例演示了这种情况:

C#
if(pointB == true)
    //Error CS1023:
    int radius = 5; 

将该嵌入语句放在语句块中以修复错误:

C#
if (b == true)
{
    // OK:
    System.DateTime d = System.DateTime.Now;
    System.Console.WriteLine(d.ToLongDateString());
}

嵌套语句块

语句块可以嵌套,如以下代码所示:

C#
foreach (string s in System.IO.Directory.GetDirectories(
    System.Environment.CurrentDirectory))
{
    if (s.StartsWith("CSharp"))
    {
        if (s.EndsWith("TempFolder"))
        {
            return s;
        }
    }

}
return "Not found.";

无法访问的语句

如果编译器认为在任何情况下控制流都无法到达特定语句,将生成警告 CS0162,如下面的示例所示:

C#
// An over-simplified example of unreachable code.
const int val = 5;
if (val < 4)
{
    System.Console.WriteLine("I'll never write anything."); //CS0162
}

表达式

“表达式”是由一个或多个操作数以及零个或零个以上的运算符所组成的序列,可以通过计算得到一个值、对象、方法或命名空间等结果。 表达式可以包含文本值、方法调用、运算符及其操作数,或简单名称。 简单名称可以是变量、类型成员、方法参数、命名空间或类型的名称。

表达式可以使用运算符,而运算符又可以将其他表达式用作参数,或者使用方法调用,而方法调用的参数又可以是其他方法调用,因此表达式既可以非常简单,也可以非常复杂。 下面是表达式的两个示例:

((x < 10) && ( x > 5)) || ((x > 20) && (x < 25)) 
System.Convert.ToInt32("35")

表达式值

在大部分使用表达式的上下文中,例如在语句或方法参数中,表达式应计算为某个值。 如果 x 和 y 是整数,表达式 x + y 将计算为一个数值。 表达式 new MyClass() 计算为对 MyClass 对象的新实例的引用。 表达式 myClass.ToString() 计算为一个字符串,因为字符串是该方法的返回类型。 然而,虽然命名空间名称归类为表达式,但它不计算为值,因此永远不能作为任何表达式的最终结果。 命名空间名称不能传递给方法参数,不能用在新表达式中,也不能赋值给变量。 命名空间名称只能用作较大表达式的子表达式。 同样如此的还有类型(与 System.Type 对象不同)、方法组名称(与特定方法不同)以及事件 add 和 remove 访问器。

每个值都有关联的类型。 例如,如果 x 和 y 都是 int 类型的变量,则表达式 x + y 的值的类型也是 int。 如果将该值赋给不同类型的变量,或者如果 x 和 y 是不同的类型,则应用类型转换规则。

溢出

如果值大于值类型的最大值,数值表达式可能导致溢出。

运算符的优先级和结合性

计算表达式的方式由结合性和运算符优先级控制。 有关更多信息,请参见 运算符(C# 编程指南)。
除赋值表达式和方法调用表达式之外,大部分表达式都必须嵌在语句中。

文本和简单名称

最简单的两种表达式类型是文本和简单名称。 文本是没有名称的常数值。 例如,在下面的代码示例中,5 和 “Hello World” 都是文本值:

C#
// Expression statements.
int i = 5;
string s = "Hello World";

在上面的示例中,i 和 s 都是用于标识局部变量的简单名称。 在表达式中使用这些变量时,变量名称计算为当前在该变量的内存位置所存储的值。 下面的示例演示了这种情况:

C#
int num = 5;
System.Console.WriteLine(num); // Output: 5
num = 6;
System.Console.WriteLine(num); // Output: 6   

调用表达式

在下面的代码示例中,对 DoWork 的调用是一个调用表达式。

DoWork();

方法调用要求使用方法的名称(如前面的示例中那样作为名称,或作为其他表达式的结果),后跟括号和任意方法参数。 委托调用使用委托的名称和括号内的方法参数。 如果方法返回值,则方法调用和委托调用的计算结果为该方法的返回值。 返回 void 的方法不能替代表达式中的值。

查询表达式

有关常规表达式的规则同样适用于查询表达式。

Lambda 表达式

Lambda 表达式表示没有名称但可以具有输入参数和多个语句的“内联方法”。 它们在 LINQ 中广泛用于向方法传递参数。 Lambda 表达式被编译为委托或表达式树,具体取决于使用它们的上下文。

表达式树

使用表达式树可以将表达式表示为数据结构。 表达式树由 LINQ 提供程序广泛使用,用来将查询表达式转换为在其他某个上下文(如 SQL 数据库)中有意义的代码。

备注

只要从表达式中识别到变量、对象属性或对象索引器访问,该项的值都会用作表达式的值。 在 C# 中,只要表达式的最终计算结果是所需的类型,表达式就可以放置在任何需要值或对象的位置。

运算符

在 C# 中,运算符是应用于表达式或语句中的一个或多个操作数的程序元素。 接受一个操作数的运算符称为一元运算符,例如递增运算符 (++) 或 new。 接受两个操作数的运算符称为二元运算符,例如算术运算符(+、-、*、/)。 条件运算符 ?: 接受三个操作数,是 C# 中唯一的三元运算符。

下面的 C# 语句包含一个一元运算符和一个操作数。 递增运算符 ++ 修改操作数 y 的值。

C#
y++;

下面的 C# 语句包含两个二元运算符,它们分别有两个操作数。 赋值运算符 = 将一个整数变量 y 和一个表达式 2 + 3 作为操作数。 表达式 2 + 3 本身由加法运算符和两个操作数 2 和 3 组成。

C#
y = 2 + 3;

运算符、计算和运算符优先级

操作数可以是由任何长度的代码组成的有效表达式,且可包含任意数量的子表达式。 在包含多个运算符的表达式中,运算符的应用顺序由运算符优先级、关联性和括号确定。

每个运算符都具有已定义的优先级。 在包含具有不同优先级级别的多个运算符的表达式中,运算符的优先级确定运算符的计算顺序。 例如,下列语句将 3 赋给 n1。

n1 = 11 - 2 * 4;

因为乘法的优先级高于减法,所以首先执行乘法。
下表根据运算符执行的操作类型将它们划分到不同的类别中。 类别按优先级顺序列出。
主要运算符
这里写图片描述
一元运算符
这里写图片描述
乘法运算符
这里写图片描述
相加运算符
这里写图片描述
移位运算符
这里写图片描述
关系和类型运算符
这里写图片描述
相等运算符
这里写图片描述
逻辑、条件和 null 运算符
这里写图片描述
赋值和匿名运算符
这里写图片描述

结合性

当表达式中出现两个或两个以上具有相同优先级的运算符时,将根据结合性计算它们。 左结合运算符按从左到右的顺序计算。 例如,x * y / z 将计算为 (x * y) / z。 右结合运算符按从右到左的顺序计算。 例如,赋值运算符是右关联的。 如果不是,下面的代码将导致错误。

C#
int a, b, c; c = 1; // The following two lines are equivalent. 
a = b = c; 
a = (b = c); // The following line, which forces left associativity, causes an error. 
             //(a = b) = c;

再举一个例子,三元运算符 (?:) 是右结合运算符。 大多数的二元运算符是左结合运算符。

无论表达式中的运算符是左结合运算符还是右结合运算符,都将先从左至右评估各表达式的操作数。 以下示例显示运算符和操作数的计算顺序。
这里写图片描述

添加括号

可通过使用圆括号更改运算符优先级和相关性。 例如,2 + 3 * 2 通常计算结果为 8,因为乘法运算符的优先级高于加法运算符。 但是,如果你将表达式编写为 (2 + 3) * 2,则先计算加法,再计算乘法,且结果为 10。 以下示例显示括号表达式中的计算顺序。 如前面的示例中所示,计算操作数之前会应用运算符。
这里写图片描述

运算符重载

对于自定义类和结构,你可以更改运算符的行为。 此过程称为“运算符重载”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值