C#学习笔记(十)CSharp表达式与语句(二)ildasm打开反编译器+foreach本质

语句Statements. 

语句等价于一个或一组有明显逻辑关联的指令

在汇编语言的书《Assembly Language step by step》中有一句话:

像Pascal或者C++这类语言的编译器的功能:就是去决策如何把给定的一些语句翻译成一系列的机器语言的指令

如何查看Csharp编译后的低级汇编语言:

右键【项目名称】选择【在文件资源管理器中打开文件夹】中,选择【bin】下【Debug】下的exe文件。将应用文件复制到桌面。

C#学习笔记(十)CSharp表达式与语句(二)ildasm打开反编译器+foreach本质_第1张图片

然后子【win】中搜索visual Studio Tools

C#学习笔记(十)CSharp表达式与语句(二)ildasm打开反编译器+foreach本质_第2张图片

双击打开。实际上是一个命令行,为我们加载了一系列必要工具。在命令行中我们输入ildasm回车。(il叫中间语言,dasm叫反编译。)打开了IL DASM工具软件。这个工具帮助我们查看,编译好的Csharp的低级源代码。

C#学习笔记(十)CSharp表达式与语句(二)ildasm打开反编译器+foreach本质_第3张图片

打开我们在桌面上复制好的exe。查看,可以看到命名空间和类,以及类下的方法名称。但是因为低级语言照顾的是机器,不是人类,所以很难读懂。

高级语言中的表达式对应低级语言中的指令。

一组表达式组成一个语句,一个语句等价于一个或一组有明显逻辑关联的指令。

 C#中语句的定义:程序执行的动作是由语句来表达的。语句有以下功能:

1、声明变量;declaring variables

2、对变量赋值;assigning values

3、调用函数;calling methods

4、集合中循环;looping through collections

5、根据给定的条件在分支之间跳转:branching to one or another block of code ,depending on a given conditon。

语句的执行顺序称为:控制流或者执行流。

语句简言之:陈述算法思想、控制逻辑走向、完成有意义的动作(Action)。

C#中语句由分号结尾,但是由分号结尾的不一定都是语句。比如程序开头使用using System;这个不是语句,这个是using指令。通过指令引入了名称空间。

class student
{
    public string Name;  //也不是语句,这叫字段的声明。不叫字段的声明语句。
}

语句一定是出现在方法体中。语句一定出现在方法体中。



语句详解

语句Statement有三大类:

  • 标签语句labeled-statement:不多见

  • 声明语句declaration-statement:声明变量、常量。

  • 嵌入式语句embedded-statement: 一个大类别,分为以下几类。

标签语句:

//标签语句。
hello: Console.WriteLine("hello world");
goto hello;

嵌入式语句Embedded-statement:

  • 1、声明语句:声明语句由两部分构成,一部分是数据类型,一部分是变量声明器。int x; var y;   int就是type类型声明,var是另一类需要编译器猜测的数据类型。x和y就是声明器。后面也可以跟一个初始化器。int x =100;

    • 局部变量声明
    • 局部常量声明:一旦声明,不希望值再改变。const int x =100;常量声明的时候,必须初始化值。

面试题:以下两个语句是不是一回事。

int x =100;
int x;
x = 100;

第一种情况:int x =100;是声明变量时,追加初始化器。

第二种情况:声明的时候没有初始化,而在后面对变量进行赋值。

前面是一步操作,后面是两步操作。

// 数组初始化器:一对花括号,然后里面写上元素。
int[] myArray = {1,2, 3};
//整型数组类型。
  • 2、表达式语句:由表达式计算出来的值(如果有)被丢弃。只关心动作,不关心结果。
Console.WriteLine       // 这叫成员访问,不叫方法调用。
Console.WriteLine("方法调用表达式语句:invacation-expression");     // 调用,重载决策。

对象创造表达式:object-creation-expression:new操作符,会创建一个对象,然后调用对象的构造器。new Form();没有任何赋值给任何变量来接收承载,很快gcc就把他回收了,但仍是一条语句。

赋值表达式:assignment

后、前置自增表达式:x++;++x;

后、前置自减表达式:x--;--x;

await-expression:在异步中讲解。

  • 3、块语句block:用于在只允许使用单个语句的上下文中编写多条语句。写在花括号{中}。

并非所有的花括号都是块,平时用于构造名称空间体、类体、方法体。

因为语句一定也只能出现在方法体中。所以方法体中的花括号才可以考虑是不是块。

1)块语句的花括号中,不论有多少语句,编译器都看做为一条语句。

2)块语句后不需要加分号。

VS使用小技巧:按【Ctrl】再按【右花括号】。可以在VS中,找到成对的花括号。阅读程序时很方便。在开始和结束之间反复跳动。

变量的作用域:块中的变量可以访问到同一方法下的其他变量,其他变量不可以访问到块中的变量。块中变量,出了块,没用了。

int x = 100;
{
    Console.WriteLine(x);
    int y = 200;
    Console.WriteLine(y);
}
//Console.WriteLine(y);

// 100
// 200
最外面的Console.WriteLine无法编译通过。
  • 4、选择(判断、分支)语句selection-statement: 

if 语句:if语句中只能放入嵌入式语句,而且只能放一条。如果放入的逻辑比较复杂怎么办?上面所讲嵌入式语句中有一种叫块语句(语句的容器:把多条语句,整合成一条语句)

int x = 200;
int y = 100;
if (x

不论条件是否成立:第二个cw都会打印出来。因为if只能控制一条语句。第二条不归他管。为了执行多条语句:此时需要引入块语句。

小技巧:建议:在任何时候使用if语句都使用块语句。同时在VS借用编译器if按两下tab键自动补全结构。

switch语句:switch表达式的类型为:sbyte、byte、short、ushort、int、uint、long、ulong、bool、char、string、enum-type。不可以为double类型。case后接的必须是const值。 

class Program
{
    static void Main(string[] args)
    {
        Level myLevel = Level.High;
        switch (myLevel)
        {
            case Level.High:
                break;
            case Level.Mid:
                break;
            case Level.Low:
                break;
            default:
                break;
        }
    }
}

enum Level
{
    High,
    Mid,
    Low
}

小技巧:在VS编译器中,输入switch连续按两下tab键,即可自动补全switch结构,然后将switch(switch_on)中替换成myLevel直接按回车,就会自动补全剩下内容。

建议:在写switch时,无论什么时候,都建议将default写出来,以免意想不到的逻辑发生。

  • 5、try语句
  • 6、迭代(循环)语句:iteration-statement

while语句

List intList = new List() { 1, 2, 3, 4, 5, 6, 7, 8 };
IEnumerator enumerator = intList.GetEnumerator();
while (enumerator.MoveNext())
{
    Console.WriteLine(enumerator.Current);
}

//enumerator.Reset();
while (enumerator.MoveNext())
{
    Console.WriteLine(enumerator.Current);
}

for语句

do..while语句

foreach语句:最适合对集合进行遍历。

  • 7、跳转语句:jump-statement

continue语句:放弃当前这次循环,立刻开始下一轮循环。

break语句:立即结束循环语句。

只能跳转当前所在层的循环,无法影响外层循环。

return语句:今早使用原则:可以让读代码的人,最短的时候内知道目的。


foreach语句拓展:(为P29显示接口隔离,重新整理一遍)

集合的遍历两个问题:1、什么样的集合可以被遍历?2、迭代器。

在C#语言中,所有数组的基类都是Array。

int[] intArray = new[] {1, 2, 3, 4, 5, 6, 7};
Console.WriteLine(intArray.GetType().FullName);
Console.WriteLine(intArray is Array);

输出

System.Int32[]
True

右键Array,转到定义(或直接按F12)。看一下它实现了哪些接口。

C#学习笔记(十)CSharp表达式与语句(二)ildasm打开反编译器+foreach本质_第4张图片

其中IEnumerable就是可以被遍历的集合。转入IEnumerable的定义。里面只有唯一的一个GetEnumerator方法,获取集合迭代器。Enumerator就是迭代器。C#中所有可以迭代的集合,都能够获得自己的迭代器。

C#学习笔记(十)CSharp表达式与语句(二)ildasm打开反编译器+foreach本质_第5张图片

再看一个泛型的list。

List listInt = new List() { 1, 2, 3, 4, 5, 6, 7 };

它也实现了IEnumerable接口。

第一个问题解决了,什么样的集合可以迭代,来使用foreach来遍历。

我们来添加一个新的名称空间的引用。

using System.Collections;

以接口作为一个类型声明一个变量:获取整型数组的迭代器。

IEnumerator enumerator = intArray.GetEnumerator();

什么叫迭代器?

将鼠标右键:IEnumerator。或者直接按F12。查看定义:里面有一个MoveNext方法。返回值是bool类型的值。如果迭代器可以往后移动,拿到下一个数,就返回True。如果拿不到就到此为止。只读Current属性就代表当前访问的元素。reset就是把迭代器拨回到最开始的位置。这就是迭代器。

C#学习笔记(十)CSharp表达式与语句(二)ildasm打开反编译器+foreach本质_第6张图片

static void Main(string[] args)
{
    int[] intArray = new[] { 1, 2, 3, 4, 5, 6, 7 };
    IEnumerator enumerator = intArray.GetEnumerator();//指月
    while (enumerator.MoveNext())
    {
        Console.WriteLine(enumerator.Current);
    }
    // enumerator.Reset();
    while (enumerator.MoveNext())
    {
        Console.WriteLine(enumerator.Current);
    }
}

结果只打印一次遍历结果,因为当执行一遍while之后,迭代器已经指向了最后一个元素。再一次访问,Next返回值为false。所以第二遍不会打印。如果我们调用enumerator.Reset()方法,就可以拨回到集合的最开始。此时可以打印两次。

foreach循环就是对集合遍历的简记法。foreach中的迭代变量就相当于我们的迭代器中的enumerator.Current。

 

你可能感兴趣的:(编程语言C#)