- 表达式定义
- 表达式概览
- 语句定义
- 语句详解
表达式定义
什么是表达式
Expressions, together with commands and declarations, are one of the basic components of every rogramming language.We can say that expressions are the essential component of every language.
An expressions is a syntactic entity (语法实体)whose evaluation either produces a value or fails to terminate, in which case the expression is undefined.
各种编程语言对表达式的实现不尽相同,但大体上都符合这个定义
C#语言对表达式的定义
An expression is a sequence of one or more operands and zero or more operators that can be evaluated to a single value, object, method, or namespace.
int x;
x = 100;
// single value
(new Form()).showDialog();
//object
Action myAction = new Action(Console.WriteLine);
//method
System.Windows.Forms.Form myForm = new Forms();
//namespace
Expressions can consist of a literal value, a method invocation, an operator and its operands, or a simple name.Simple names can be the name of a variable type member, method parameter,namespace or type.
算法逻辑的最基本(最小)单元,表达一定的算法意图
因为操作符有优先级,所以表达式也就有了优先级
表达式概览
C#语言中表达式的分类
- A value.Every value has an associated type(任何值都有一个关联类型).任何能得到值的运算(回顾操作符和结果类型)
操作数的类型不代表最终结果的type是一致的。
- A variable.(变量)Every variable has an associated type.
- A namespace.
- A type.
- A method group(方法组).例如:Console.WriteLine, 这是一组方法, 重载决策决定具体调用哪一个
- A null literal(空值).
- An anonymous function(匿名函数).
- A property access.
- An event access.
- An indexer access.
- Nothing.对返回值为void的方法的调用
表达式返回值概述
x.y
操作符
返回值的类型由所访问的成员类型决定返回值的类型
static void Main(string[] args)
{
Student stu = new Student();
var x = stu.name; //x的type为string
var y = stu.age; //y的type为int32
}
class Student
{
public string name;
public int age;
}
f(x)
操作符
返回值的类型由f(x)中的f决定。
static void Main(string[] args)
{
var x = Math.Pow(2, 3);//pow的类型为double,所以,x的类型为double
Console.WriteLine(x.GetType ().Name );
}
a[x]
操作符
由集合类型所决定
static void Main(string[] args)
{
List<int> intlist = new List<int>() { 1,2,3};
double[] doubleList = new double[] { 1.0, 2.0, 3.0 };
var x = intlist[1]; //x为int
var y = doubleList[1]; //y为double
Console.WriteLine(x.GetType());
Console.WriteLine(y.GetType());
}
x++ x-- ++x --x
操作符
表达式的类型和x的类型一致。
表达式的值需要与 操作数的值区分开typeof
操作符
返回值固定,为type。default
操作符
所操作的数据值类型
static void Main(string[] args)
{
var x =default (int);
Console.WriteLine(x);
Console.WriteLine(x.GetType().FullName );
}
checked unchecked
操作符
表达式与操作数的类型一致
static void Main(string[] args)
{
var x = checked(123 + 456);
Console.WriteLine(x.GetType().FullName );
}
!
操作符
为布尔类型~
操作符
表达式与操作数的类型一致(T)x
操作符
表达式类型与需要转换类型一致* / + - %
算数运算操作符
在不发生“数值提升”的前提下,表达式类型与需要转换类型一致;
发生之后,与精度最高的操作数保持一致;<< >>
操作符
与操作符左侧的操作数类型保持一致
static void Main(string[] args)
{
long x = 100;
Console.WriteLine((x<<2).GetType ().FullName );
}
is
操作符
为布尔类型as
操作符
as成功,类型与操作符右侧的操作数保持一致;
不成功,返回Null;& ^ |
操作符
与操作数保持一致&& ||
操作符
为布尔类型,且操作数需要为布尔类型??
Null合并操作符
表达式的数据类型就是??
左侧操作数的数据类型。
static void Main(string[] args)
{
int? x = null;
//int?完整写法:Nullable<int> x =null;
var y = x ?? 100;
Console.WriteLine(y.GetType().FullName);
}
? :
条件操作符
由符号左右两侧操作数决定,精度高决定
static void Main(string[] args)
{
var x = 5 > 3 ? 2 : 3.0;
Console.WriteLine(x);
Console.WriteLine(x.GetType().FullName);
}
//在 : 两边的操作数的类型必须可以进行隐式转换
复合表达式的求值
参考C#语言定义文档
语句定义
Wikipedia对语句的定义
In computer programming a statement is the smallest standalone (最小的独立元素)element of an imperative programming language which expresses some action to be carried out.A program written in such a language is formed by a sequence of one or more statements.A statement will have internal components(e.g., expressions) .
语句是高级语言的语法——编译语言和机器语言只有指令(高级语言中的表达式对应低级语言中的指令),语句等价于一个或一组有明显逻辑关联的指令。举例:求圆柱体积。
#include<stdio.h>
double getCylindeVolume(double r,double h)
{
double area=3.14159*r*r;
double volume =area*h;
return volume;
}
int main()
{
double result = getCylinderVolume(10,100);
printf("Volume = %f\n",result);
retuen 0
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CSharpApp
{
class Program
{
static void Main(string[] args)
{
double result = GetCylinderVolume(10,100);
Console.WriteLine(result);
}
static double GetCylinderVolume(double r ,double h)
{
double area = 3.1416 * r * r;
double volume =area * h;
return volume;
}
}
}
C# 看汇编输出
1. 找到编译的 Application![](https://cdn.nlark.com/yuque/0/2018/png/101969/1542074120324-48379e29-07e6-4536-bd9c-c8577acdc817.png#crop=0&crop=0&crop=1&crop=1&height=157&id=xbklX&originHeight=157&originWidth=594&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=594)
1. 在电脑里面搜索找到 Developer Command Prompt![](https://cdn.nlark.com/yuque/0/2018/png/101969/1542074134249-4681c4a7-8547-47b0-8e9d-5379d949ee7d.png#crop=0&crop=0&crop=1&crop=1&height=181&id=RsMQf&originHeight=181&originWidth=588&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=588)
1. 输入 ildasm 命令![](https://cdn.nlark.com/yuque/0/2018/png/101969/1542074150290-521061c4-7044-4161-b92a-f42bab624cc8.png#crop=0&crop=0&crop=1&crop=1&height=230&id=R8EMQ&originHeight=295&originWidth=1025&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=799)
1. 用 ildasm 工具打开第 1 步找到的 Application![](https://cdn.nlark.com/yuque/0/2018/png/101969/1542074164208-52cda7f8-6338-4d61-9f9c-cddac7804365.png#crop=0&crop=0&crop=1&crop=1&height=591&id=Bgp1s&originHeight=591&originWidth=382&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=382)
1. 双击具体方法,查看编译结果![](https://cdn.nlark.com/yuque/0/2018/png/101969/1542074179651-69139f4e-f492-470f-9696-5230f328af67.png#crop=0&crop=0&crop=1&crop=1&height=480&id=dbepY&originHeight=602&originWidth=1003&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=799)
C#语言对语句的定义
The actions that a program takes are expressed in statements.Common actions include declaring variables, assigning values, calling methods, looping through collections, and branching to one or another block of code, depending on a given condition.The order in which statements are executed in a program is called the flow of control or flow of execution. The flow of control may vary everytime that a program is run, depending on how the program reacts to input that it receives at runtime.
C#语言的语句除了能够让程序员”顺序地”(sequentially) 表达算法思想, 还能通过条件判断、跳转和循环等芳法控制程序逻辑的走向
简言之就是:陈述算法思想, 控制逻辑走向, 完成有意义的动作(action)
C#语言的语句由分号(;)结尾,俱由分号结尾的不一定都是语句
语句一定是出现在方法体里
using system; //指令
class Student
{
public string name; //字段的声明
}
实例演示控制流(flow of control)
static void Main(string[] args)
{
string input = Console.ReadLine();
try
{
double score = double.Parse(input);
if (score >= 60)
{
Console.WriteLine("Pass!");
}
else
{
Console.WriteLine("Failed!");
}
}
catch
{
Console.WriteLine("Not a number!");
}
}
语句详解
statement:
labeled-statement 标签语句,用得不多
declaration-statement (声明语句)
- 局部变量声明
数据类型:type、var
int x=100;
var y =2; //var声明变量之后,无法更改数据类型
int x;
x =100;
int x = 100;
两者具有差异,前者没有使用初始化器,适用赋值对x进行更改;后者是使用初始化器
- 局部常量声明
常量表示声明并且初始化之后不能更改的数据;
namespace world
{
class Program
{
static void Main(string[] args)
{
const int x = 200;
x = 500; //此处运行会报错,原因是由于x不是变量;一旦常量初始化之后
//就不能更改该常量的数值。
const int y; //此处运行会报错,原因是由于声明x常量的同时需要对y使用初始化器
}
}
}
embedded-statement 嵌入式语句
embedded-statement:
block(块语句)
:::info
block用于在只允许使用单个语句的上下文中编写多条语句。
block:
{statement-listopt}
block由一个扩在大括号内的可选statement-list组成。如果没有此语句列表, 则称块是空的。
块可以包含声明语句。在一个块中声明的局部变量或常量的范围就是该块本身。
:::
static void Main(string[] args)
{
int x = 100;
{
Console.WriteLine(x);
int y = 200;
Console.WriteLine(y);
}
// Error CS0103 当前上下文中不存在名称“y”
Console.WriteLine(y);
}
:::info
在块内,在表达式上下文中使用的名称的含义必须始终相同。
块按下述规则执行:
如果块是空的,控制转到块的结束点。
如果块不是空的,控制转到语句列表。当控制到达语句列表的结束点时,控制转到块的结束点。
如果块本身是可到达的,则块的语句列表是可到达的。
如果块是空的或者如果语句列表的结束点是可到达的,则块的结束点是可到达的。
包含一条或多条yield语句的block称为迭代器块。迭代器块用于以迭代器的形式实现函数成员。某些附加限制适用于迭代器块:
迭代器块中出现return语句时会产生编译时错误(但允许yie1d return语句) 。
迭代器块包含不安全的上下文(第18.1节)时将导致编译时错误。迭代器块总是定义安全的上下文,即使其定义嵌套在不安全的上下文中也如此。
:::
- 块语句无论什么时候都被编译器当做一条语句来看待
-
empty-statement(空语句)
expression-statement(表达式语句)
static void Main(string[] args)
{
Console.WriteLine("hello world"); //方法调用表达式+“;”形成语句
new Programing(); //使用new操作符创建对象+“;”形成语句
int x;
x = 100; //赋值表达式+“;”形成语句
x++;
x--;
++x;
--x; //前增减、后增减+“;”形成语句
}
expression-statement 用于计算所给定的表达式。由此表达式计算出来的值(如果有)被丢弃。 ```csharp static void Main(string[] args) { // Add 产生的 7.0,如果前面没有拿变量接收它,值被丢弃了。 Add(3.0, 4.0); }
static double Add(double a,double b) { return a + b; }
不是所有的表达式都允许作为语句使用。具体而言,不允许像x+y和x==1这样只计算一个值(此值将被放弃)的表达式作为语句使用。<br />执行一个expression-statement就是对包含的表达式进行计算, 然后将控制转到该expression-statement的结束点。如果一个expression-statement是可到达的, 则expression-statement结束点也是可到达的。<br />**Single Responsibility** 单一职责原则:一个方法尽量只做一件事情。
<a name="AorkU"></a>
### selection-statement(选择为语句)
选择语句会根据表达式的值从若看个给定的语句中选择一个来执行。
<a name="ssDtv"></a>
#### `if`语句
![1542074514803-0cf8bca8-eafb-498f-bfbb-a226cc3a7006.png](https://cdn.nlark.com/yuque/0/2022/png/26207277/1645769303293-573c4b63-069e-4410-bda3-8fc2ab19bb39.png#clientId=ube940525-d288-4&crop=0&crop=0&crop=1&crop=1&from=ui&id=u84313260&margin=%5Bobject%20Object%5D&name=1542074514803-0cf8bca8-eafb-498f-bfbb-a226cc3a7006.png&originHeight=402&originWidth=825&originalType=binary&ratio=1&rotation=0&showTitle=false&size=202845&status=done&style=none&taskId=u9602df6f-d65d-47a5-93e7-4affb72c464&title=)<br />无论多长的 `if else`,它都是一条语句。之所以能有 `else if{}` 这种结构,也是因为 `if{}` 是一条语句。
<a name="Xp5s0"></a>
#### `switch`语句
![image.png](https://cdn.nlark.com/yuque/0/2022/png/26207277/1645769519397-0bcb6a23-61ae-4a26-9d15-1afb9403dea7.png#clientId=ube940525-d288-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=u662d5a91&margin=%5Bobject%20Object%5D&name=image.png&originHeight=504&originWidth=825&originalType=binary&ratio=1&rotation=0&showTitle=false&size=257813&status=done&style=none&taskId=u87031ecc-c94d-42e2-9b80-ed429074ddd&title=)
> **注**:从 C# 7.0 开始 switch 表达式已[支持任何非 null 表达式](https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/switch#the-match-expression)。
```csharp
using System;
namespace world
{
class Program
{
static void Main(string[] args)
{
double score = 99;
switch ((int)(score / 10))
{
case 10:
if (score == 100)
{
goto case 8;
}
else
{
goto default;
}
case 9:
//Console.WriteLine("A");两个标签内的语句不能相同,需要相同输出时,可如同7./6.示例
case 8:
Console.WriteLine("A");
break;//C#中标签条件内不能丢失break语句.一旦有了具体的 section,就必需配套 break。
case 7:
case 6:
Console.WriteLine("B");
break;
case 5:
case 4:
Console.WriteLine("C");
break;
case 3:
case 2:
case 1:
case 0:
Console.WriteLine("D");
break;
default://效果类似于if else中的else
break;
}
}
}
}
iteration-statement(迭代/循环语句)
while
语句
- while 语句按不同条件执行一个嵌入语句零次或多次 ```csharp using System; using System.Collections.Generic;
namespace StatementsExample { class Program { static void Main(string[] args) { int score = 0; bool canContiue = true; while (canContiue) { Console.WriteLine(“Please input the first number”); string str1=Console.ReadLine(); int x=int.Parse(str1);
Console.WriteLine("Please input the second number");
string str2 = Console.ReadLine();
int y = int.Parse(str2);
int sum = x + y;
if(sum ==100)
{
score++;
Console.WriteLine("correct!{0}+{1}={2}",x,y,sum);
}
else
{
Console.WriteLine("Error!{0}+{1}={2}",x,y,sum);
canContiue = false;
}
}
Console.WriteLine("your score is {0}",score);
Console.WriteLine("good game!");
}
}
}
<a name="o5NtC"></a>
#### `do`语句
- do 语句按不同条件执行一个嵌入语句一次或多次
代码见`[break、continue语句](https://www.yuque.com/dingxuchen/cc9wwf/wezf1n/edit)`
<a name="EJNRJ"></a>
#### `for`语句
- for 语句计算一个初始化表达式序列,然后,当某个条件为真时,重复执行相关的嵌入语句并计算一个迭代表达式序列
```csharp
using System;
using System.Collections.Generic;
namespace StatementsExample
{
class Program
{
static void Main(string[] args)
{
for (int i = 1; i <=9; i++)
{
for (int j = 1; j <=i; j++)
{
Console.Write("{0}*{1}={2}\t", i, j, i * j);
}
Console.WriteLine();
}
}
}
}
foreach
语句
- foreach 语句用于枚举一个集合的元素,并对该集合中的每个元素执行一次相关的嵌入语句
集合遍历的底层原理和迭代器,foreach 语句就是对集合遍历的简记法。
using System;
using System.Collections;
using System.Collections.Generic;
namespace StatementsExample
{
class Program
{
static void Main(string[] args)
{
int[] intArray = new int[] { 1, 2, 3, 4, 5, 6 };
// Console.WriteLine(intArray.GetType().FullName);
// Console.WriteLine((intArray is Array));
IEnumerator enumerator = intArray.GetEnumerator();//指月
while(enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}
enumerator.Reset();//重复输出解决办法
while(enumerator.MoveNext()) // 重复使用迭代器进行输出,
//结果任然为一次循环输出,原因是因为第一次输出后, 指针已经指向了最后一个数,无法跳转到
//第一个数进行重复输出
{
Console.WriteLine(enumerator.Current);
}
//List<int> intList = new List<int> { 1, 2, 3, 4, 5, 6 };
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
namespace StatementsExample
{
class Program
{
static void Main(string[] args)
{
int[] intArray = new int[] { 1, 2, 3, 4, 5, 6 };
List<int> intList = new List<int>(){ 1,2,3,4,5,6};
foreach (var current in intList)
{
Console.WriteLine(current);
}
}
}
}
jump-statement(跳转语句)
continue
语句
continue 语句将开始直接封闭它的 while、do、for 或 foreach 语句的一次新迭代
break
语句break 语句将退出直接封闭它的 switch、while、do、for 或 foreach 语句 ```csharp using System; using System.Collections.Generic;
namespace StatementsExample
{
class Program
{
static void Main(string[] args)
{
int score = 0;
int sum = 0;
do
{
Console.WriteLine(“Please input the first number”);
string str1 = Console.ReadLine();
int x=0;
if (str1.ToLower() ==”end”|| str1.ToLower() == “END”)
{
break;
}
try
{
x = int.Parse(str1);
}
catch
{
Console.WriteLine(“First number has probleam!Restart”);
continue;
}
Console.WriteLine(“Please input the second number”);
string str2 = Console.ReadLine();
int y=0;
if (str2.ToLower() == “end” || str1.ToLower() == “END”)
{
break;
}
try
{
y = int.Parse(str2);
}
catch
{
Console.WriteLine(“Second number has probleam!Restart”);
continue;
}
sum = x + y;
if (sum == 100)
{
score++;
Console.WriteLine(“correct!{0}+{1}={2}”, x, y, sum);
}
else
{
Console.WriteLine(“Error!{0}+{1}={2}”, x, y, sum);
}
}while(sum==100);
Console.WriteLine(“your score is {0}”, score);
Console.WriteLine(“good game!”);
}
}
}
<a name="N2gDW"></a>
#### `goto`语句
- goto 语句将控制转到由标签标记的语句
- goto 语句基本被淘汰
<a name="nnhZq"></a>
#### `throw`语句
- throw 语句将引发一个异常
- throw 语句语法比较灵活,它后面可以什么都不跟
<a name="vyeZ8"></a>
#### `return`语句
- return 语句会将控制返回到出现 return 语句的函数的当前调用方
- 提前 return 原则
- 方法的每个分支里面都需要有 return
**提前return原则**<br />通过提前 return 可以让代码阅读者立刻就鉴别出来程序将在什么情况下 return,同时减少 if else 嵌套,写出更优雅的代码。
```csharp
class Program
{
static void Main(string[] args)
{
Greeting("Mr.Duan");
}
static void Greeting(string name)
{
if (string.IsNullOrEmpty(name))
{
// 通过尽早 return 可以让代码阅读者立刻就鉴别出来
// name 参数在什么情况下是有问题的
return;
}
Console.WriteLine("Hello, {0}", name);
}
}
try-statement(try…catch…finally语句)
:::info
try语句提供一种机制, 用于捕捉在块的执行期间发生的各种异常。此外, try语句还能让您指定一个代码块, 并保证当控制离开try语句时, 总是先执行该代码。
try-statement:
try block catch-clauses
try block finally-clause
try block catch-clauses finally-clause
catch-clauses:
specific-catch-clauses general-catch-clause opt
specific-catch-clausesopr general-catch-clause
specific-catch-clauses:
specific-catch-clause
specific-catch-clauses specific-catch-clause
specific-catch-clause:
catch( class-type identifieropt)block
general-catch-clause:
catch block
finally-clause:
finally block
有三种可能的try语句形式:
一个try块后接一个或多个catch块。
一个try块后接一个finally块。
一个try块后接一个或多个catch块, 后面再跟一个finally块。
:::
可以通过 MSDN 查方法相应的异常。
如 Int32.Parse 方法 (String) 就有以下异常。
- 应该把释放系统资源的语句写在 finally block 里面
- 有时候也在 finally block 里面写 log
using System;
using System.Collections.Generic;
namespace StatementsExample
{
class Program
{
static void Main(string[] args)
{
Calculator c = new Calculator();
int r = c.Add("999999999999", "200");
Console.WriteLine(r);
}
class Calculator
{
public int Add(string arg1,string arg2)
{
int a = 0;
int b = 0;
bool hasError = false;
try
{
//int a = int.Parse(arg1);
//int b = int.Parse(arg2);
//局部变量的数据范围不会超出语句块,当使用上述注释语句块,结果为0
//因此需要在try语句块之外对变量进行声明
a =int.Parse(arg1);
b=int.Parse(arg2);
}
catch (FormatException ane)//此处"ane"变量是对FormatException进行调用
{
Console.WriteLine("your arguments are not number");
Console.WriteLine(ane.Message);//当触发此异常时,会对错误进行详细报错
hasError = true;
}
catch(OverflowException)
{
Console.WriteLine("out of range!");
hasError = true;
}
catch(ArgumentException)
{
Console.WriteLine("your arguments are null");
hasError = true;
}
catch//在catch子句之后()内不填写任何类型,说明是通用异常,使用其他说明是针对某一类型的异常进行报错
{
Console.WriteLine("your argunments are error");
hasError = true;
}
finally//不管上述try语句是否执行,是否发生异常,最终都会执行finally语句
{
//会申请系统资源,如释放资源
//书写程序记录
if(hasError)
{
Console.WriteLine("Execution has error");
}
else
{
Console.WriteLine("Done!");
}
//优势:当程序执行时,出现是否发生异常提示,若未发生异常,则程序执行结果为正常结果
}
int result = a + b;
return result;
}
}
}
}
throw
throw 将异常抛给调用者。
throw 关键字的语法比较灵活
try
{
...
}
catch(OverflowException)
{
throw;
}