using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
public class 核心
{
#region MyRegion
/*
关键字KeyWord
操作符Operator
标识符Identifier]什么事合法的标识符
大小写规范
命名规范
标点符号
文本值
整数 多种后缀
实数 多种后缀
字符
字符串
不二
空
注释与空白
单行与多行
Token
int x = 2;//32bit
long y = 3L;//64bit
//0~99 9999数字范围越广
float x1 = 3.0F;
double y1 = 4.0D;
char c = 'a';//字符文本
string str = "dfsdfd";//空的 一个字符
bool vb = true;
bool b2 = false;
string str1 = "helloworld";//没有任何值
Form f = new Form();
f.ShowDialog(); */
/*
*
块注释 大家注意一点 行注释 注释失败 语法有错
*/
//var x2 = 3.0F;
//Console.WriteLine(x2.GetType().Name);
//Console.ReadLine();
/*
变量函数
初识类型Type
也称数据类型DataType
变量是存放数据的地方,简称数据
变量的声明
变量的使用
方法就成函数是处理数据的逻辑,又称算法
方法的声明
方法的调用
程序=数据+算法
有了变量和方法就可以写有意义的程序了
*/
//double x;
//x = 3.0;//要一个整形变量 容器装数 字面值 相匹配 存储变量名 变量声明和使用
/*方法算法 处理数据的逻辑
一个数据的加工厂 原料
*/
//Calculator c = new Calculator();
//int result = c.Add(2,3);
//Console.WriteLine(result);
//string str = c.Today();
//Console.WriteLine(str);
//c.PrintSum(4,6);
//c.PrintTo1(3);
//int sum = c.SumFrom1ToX2(100);
//Console.WriteLine(sum);
//Console.ReadLine();
/*
算法简介
循环 递归
*/
/*
什么是类型Type
a data type us a homogenious collection of valuues,effectively presented equopped with a set of operations which manipulate these values
是数据在内存中存储时的型号
小内存容纳大尺寸数据会丢失精确度 发生错误
大内存容纳小尺寸数据会导致浪费
编程语言的数据类型与数据的数据类型不完全相同
强类型语言与弱类型语言的比较
if 条件 动态类型 C#语言对弱类型 动态类型的模仿
*/
/*
声明变量
变量的初始化和作用域
C#的预定义数据类型
在C#程序中使用条件语句、循环和跳转语句指定执行流
make module_install
make install 重要执行完能进去就行
sh ./arch/x86/boot/install.sh 4.18.0 arch/x86/boot/bzImage System.map "boot"
cd dev
reboot
.automount 用于控制自动挂载文件系统 自动挂载激荡某一目录被访问时系统自动挂载该目录 这类unit取代了
gnome图形化界面
.device 对应/dev 目录下设备 主要用于定义设备之间的依赖关系
.mount 定义系统结构层次中的一个挂载点,可以替代过去的/etc/fstab配置文件
.path 用于监控指定目录变化 并触发其他unit运行
.scope 这类unit文件不是用户创建,而是Systemd运行时自己产生的 描述一些系统服务的分组信息
.service 封装守护进程的启动、停止、重启和重载操作 是最常见的一种unit类型
.slice 用于描述cgroup的一些信息 极少使用到
.snapshot 这种unit其实是systemctl snapshot命令创建的一个描述Systemd unit运行状态的快照
.socket 监控系统或互联网中socket消息,用于实现基于网络数据自动触发服务启动
.swap 定义一个用于做虚拟内存的交换分区
.target 用于对unit进行逻辑分组 引导其他unit的执行 他替代了SysV中运行级别的作用 并提供更灵活的基于特定设备事件的启动方式
例如nulti-user.target相当于过去的运行级别5,而bluetooth.target在有蓝牙设备接入时就会被触发
.timer 封装由system的里面由时间触发的动作 替代了crontab的功能
/etc/systemd/system 系统或用户提供的配置文件
/run/systemd/system 软件运行时生成的配置文件
/usr/lib/systemd/system 系统或第三方安装时天极爱的配置文件
Service的unit文件可以分为3个配置区段,其中Unit和Install端是所有Unit文件通用的 用于配置服务或其他系统资源的描述
依赖和随系统启动方式 而Service段则是服务类型的Unit文件(后缀.Service)特有的 用于定义服务的具体管理和操作方法
其他的美中Running transaction heck
Transaction check succeedded
Running transaction
来看看每个配置段常用的参数有哪些
Description
一段描述这个Unit文件的文字 通常只是剪短的一句话
Documentation
指定服务的文档 可以使文档URL
Requires
依赖其他Unit列表 列在其中Unit模块会在这个服务启动的同时被启动
*usb*
*多了一个
Started Virtualization daemon.
grub
systemctl set-default muti-user.target
yum -y
枚举
名称空间
Main()方法
基本的命令行C#编译器选项
使用System.Console执行控制台I/O
使用内部注释和文档编制功能
预处理指令
C#编程的推荐规则和约定
理解了C#的用途后,就可以学习如何使用它了。本章介绍C#的基础知识,本章的内容也是后续章节的基础 好的开端等于成功的一半
阅读完本章后,读者就有足够的C#知识编写简单的程序了,但还不能使用继承或其他面向对象的特征。这些内容将在后面的章节中
第一个C#程序
下面编译并运行最简单的C#程序 这是一个简单的控制台应用程序 它由把某条消息写到屏幕上的一个类组成
后面几章会介绍许多代码示例 编写C#程序最常用的技巧是使用Visual Studio2010生成一个基本项目 再添加自己的项目
但是 第I部分的目的讲授C#语言 为了简单起见 在16章之前避免及Visual Studio2010 我们使代码显示为简单的文件
这样就可以用任何编辑器输入它们,并在命令行上编译
代码
在文本编辑器(如Notepad中)输入下面的戴安 把它保存为后缀名为.cs的文件(如First.cs) Main方法如下所示
编译并运行程序
对源文件进行C#命令行编译器csc.exe编译这个程序
csc First.cs
如果使用csc命令在命令行上编译代码 就应注意.NET命令行工具包括csc只有在设置了某些环境变量后才能使用 根据安装.NET和VisualStudio2010
这里显示的结果可能与您计算机上的结果不同
如果没有设置环境变量 有两种解决方法 第1中方式是在运行csc之前,从命令提示符窗口上运行批处理文件
%Microsoft Visual Studio 2010%\Common7\Tools\vsvars32.bat%其中%Microsoft Visual Studio2010%是VisualStudio2010
的安装文件夹 第2中方法更简单是使用Visual Studio2010命令提示符代替通常的命令提示窗口Visual Studio2010命令提示符在菜单开始|程序|
Microsoft Visual Studio2010|Microsoft Visual Studio Tools子菜单下 它只是一个命令提示窗口打开时会自动运行vsvars32.bat
编译代码 会生成一个可执行文件First.exe 在命令行或Windows Explorer上 像运行任何可执行文件那样运行该文件 得到如下结果
csc First.cs
详解
首先对C#语法做几个一般性的解释 在C#中与其他C风格的语言一样 大多数语句都以分号;结尾 语句可以卸载多个代码行上 不需要使用续航字符
用花括号({})把语句组合成块 单行注释以两个斜杠字符开头// 多行注释以一条斜杠和一个星号(/*)开头 以一个星号和一条斜杠
在这些方面 C#与C++和Java一样 但与Visual Basic不同 分号和花括号使C#代码与VisualBasic代码有差异很大的外观 如果您以前使用
VisualBasic就应特别注意每条语句结尾的分号 对于使用C风格语言的新用户 忽略分号常常是导致编译错误的一个最主要的原因
另一方面 C#区分大小写 也就是说变量myVar与MyVar是两个不同的变量
在上面的代码事例中 前几行代码与名称空间有关如本章后面所述 名称空间是把相关类组合在一起的方式 namespace关键字声明了应于类相关的名称空间
其中花括号中的所有代码都被认为是在这个名称空间中 编译器在using语句指定的名称空间中查找没有在当前名称空间中定义但在代码中引用的类
这非常类似于Java中的import语句和C++中的using namespace语句
using System
namespace Wrox
在First.cs文件中使用using指令的原因是下面要使用一个库类System.Console.using System语句允许把这个类简写为Console(System.名称空间中的其他类也与此类似)
如果没有using 就必须完全限定对Console.WriteLine()方法的调用如下所示
System.Console.WriteLine("Hello from Wrox.");
标准的System名称空间包含了最常用的.NET类型 在C#中做的所有工作都依赖于.NET基类
认识到这一点非常张瑶,在本例中 我们使用了System名称空间中的Console类 以写入控制台窗口
C#没有用于输入和输出的内置关键字 而是完全依赖于.NET类
几乎所有的C#程序都使用System名称空间中的类 所以假定本章所有代码文件都包含using System语句
接着 声明一个类MyFirstClass 但是 因为该类位于Wrox名称空间中 所以其完整的名称是Wrox.MyFirstCSharpClass
*/
#endregion
static int j = 20;
static void Main2(string[] args)
{
#region MyRegion
string s1 = "a string";
string s2 = s1;
Console.WriteLine("s1 is "+ s1);
Console.WriteLine("s2 is " + s2);
s1 = "another string";
Console.WriteLine("s1 is now " + s1);
Console.WriteLine("s2 is now " + s2);
Console.ReadLine();
//return 0;
/*
Console.WriteLine("Hello from wrox.");
Console.ReadLine();
return;
*/
/*
var name = "Bugs Bunny";
var age = 25;
var isRabbit = true;
Type nameType = name.GetType();
Type ageType = age.GetType();
Type isRabbitType = isRabbit.GetType();
Console.WriteLine("name is type "+ nameType.ToString());
Console.WriteLine("age is type " + ageType.ToString());
Console.WriteLine("isRabbit is type " + isRabbitType.ToString());
Console.ReadLine();*/
/*
for (int i = 0; i < 10; i++)
{
Console.Write(i);
}//i goes out of scope here
//We can declare a variable named i again,because
//there's no other variable with that name in scope
for (int i = 9; i >= 0; i--)
{
Console.Write(i);
}//i goes out of scope here
Console.ReadLine();
return 0;*/
/*
int j = 20;
for (int i = 0; i < 10; i++)
{
int j = 30;//Cant do this --j is still in scopp
Console.WriteLine(j+i);
}
Console.WriteLine();
return 0;
*/
/*
int j = 30;
Console.WriteLine(j);
return;
Console.WriteLine();
*/
/*
int j = 30;
Console.WriteLine(j);
Console.WriteLine(核心.j);
Console.ReadLine();*/
//Vector x, y;
//x = new Vector();
//x.Value = 30;//Value is a field defined in Vector class
//y = x;
//Console.WriteLine(y.Value);
//y.Value = 50;
//Console.WriteLine(x.Value);
#endregion
}
}
class MyFirstCSharpClass
{
#region MyRegion
/*
所有的C#都必须包含在一个类中 类的声明包括class关键字 其后是类名和一对花括号
与类相关的所有代码都应放在这对花括号中
下面声明方法Main每个C#可执行文件(如控制台应用程序、Windows应用程序和Window服务)都必须有一个入口点注意M大写
public staitc void Main(){
在程序启动时调用这个方法。该方法要么没有返回值(void)要么返回一个整数(int)注意在C#中方法的定义如下
[modifiers] return_type MethodName([parameters])
{
//Method body. NB . This code block is pseudo-code.
}
第一个方括号中的内容表示可选关键字 修饰符(modifiers)用于指定用户所定义的方法的某些特性 如有可以在什么地方调用该方法 在本例中 有两个修饰符
public static 修饰符public 表示可以在任何地方访问该方法 所以可以在类的外部调用它 修饰符staitc表示方法不能再累的实例上执行 因此不必先实例化类
在调用。这非常重要 因为我们创建是一个可执行文件而不是类库
把返回类型设置为void 在本例中 不包含任何参数
最后 看看代码语句
Console.WriteLine("Hello from");
Console.ReadLine();
return;
在本例中,我们只调用了System.Console类的WriteLine()方法 把一行文本写到控制台窗口上
WriteLine()是一个静态方法 在调用之前不需要实例化Console对象
Console.ReadLine()读取用户的输入 添加这行代码会让应用程序等待用户按回车键 之后退出应用程序
在Visual Studio2010中 控制台窗口会消失
然后调用return 退出该方法 因为这是Main方法 所以也退出了程序 在方法中指定void,因此没有返回值
对C#基本语法有了大致的认识后,下面就详细讨论C#的各个方面 因为没有变量不可能编写出重要的程序 所以首先介绍C#的变量
2.2 变量
在C#中声明变量使用下述语法
datatype identifier
例如
int i;
该语句声明int变量i.编译器不允许在表达式中使用这个变量,除非用一个值初始化了该变量
声明了i之后,就可以使用赋值运算符(=)给它赋值
i=10;
还可以在一行代码中声明变量 并初始化它的值
int i =10;
如果再一条语句中声明和初始化了多个变量 那么所有的变量都具有相同的数据类型
int c=20,y20;//x and y are both ints
要声明不同类型的变量 需要使用单独的语句 在多个变量的声明中 不能指定不同的数据类型
int x =10;
bool y = true;//Creates a variable that stores true or false
int x =10,bool y=true;//This won't compile
注意上面例子中的"//"和其后的文本 它们是注释 "//"告诉编译器 忽略该行后面的文本 这些文本仅为了让人更好理解程序 它们并不时程序的一部分
本章后面会详细讨论代码中的注释
2.2.1 变量初始化
变量的初始化是C#强调安全性的另一个例子。简单地说,C#编译器需要用某个初始值对变量进行初始化,之后才能在操作中引用该变量 大多数
现代编译器把没有初始化标记为警告,但C#编译器把它当做错误看待 这就可以防止我们无意中从其他程序遗留下来的内存中获取垃圾直
C#有两个方法可确保变量在使用前进行初始化
变量是类或结构中的字段 如果没有显示初始化 创建这些变量时,其默认值就是0 类和结构在后面讨论
方法的局部变量必须在代码中显示初始化 之后才能在语句中使用它们的值 此时 初始化不是在声明该变量时进行的但编译器会通过方法检查所有可能的路径
如果检测到局部变量在初始化之前就使用了它的值 就会产生错误
例如在C#中不能使用下面的语句
public static int Main()
{
int d;
Console.WriteLine(d);//Can't do this! Need to initialize d before use
return 0
}
注意这段代码中 演示了如何定义Main()使之返回一个int 类型的数据 而不是void 在编译这些代码时 会得到下面的错误消息
Use of unassigned local variable 'd'
考虑下面的语句
Something objSomething
在C#中 这行代码仅会为Something对象创建一个引用 但这个引用还没有指向任何对象 对该变量调用方法或属性会导致错误
在C#实例化一个引用对象需要使用new关键字 如上所述 创建一个引用 使用new关键字把引用指向存储在对上的一个对象
objSOme = new Something();//This creates a Something on the heap
2.2.2 类型推断
类型推断(type inference)使用var关键字 声明变量的语法有些变化。编译器可以根据变量的初始化值"推断"变量的类型 例如:
int someNumber = 0;
就变成:
var someNumber = 0;
即使someNumber从来没有声明为int ,编译器也可以确定 只要someNumber 在其作用域内
就是一个Int 编译后 上面两个语句是等价的
name is type System.String
age is type System.Int32
isRabbit is type System.Boolean
需要遵循一些规则
变量必须初始化 否则 编译器就没有推断变量类型的依据
初始化器不为空
初始化器必须放在表达式中
不能把初始化器设置为一个对象 除非在初始化器中创建了一个新对象
在第三种讨论匿名类型时将详细探讨
声明了变量 推断出了类型后 就不能改变变量类型了 变量的类型确定后 就遵循其他变量类型遵循的强类型化规则
2.23 变量作用域
变量的作用域是可以访问该变量的代码区域 一般情况下 确定作用域尊徐规则
只要类在某个作用域内 其字段也称为成员变量也在该作用域内
局部变阿宁存在于表示声明该变量的块语句或方法结束的右花括号之前的作用域内
在for while或类似语句中声明的局部白能量存在于该循环体内
1局部变量的作用域冲突
大型程序在不同部分为不同的变量使用相同的变量名很常见 只要变量的作用域是程序的不同部分就不会有问题
也不会产生多异性 但要注意 同名的局部变量不能再同意作用域内声明两次 所以不能使用下面的代码
int x =20;
//some more code
int x =30;
这段代码使用两个for循环打印0~9的数字 在逆序打0~9的数字 重要的是同一个方法中 代码中的变量i声明了两次
可以这么做的原因是在两次声明中 i 都是在循环内部声明的,所以变量i对于各自的循环来说是局部变量
下面是另一个例子
如果视图编译它 就会产生如下错误
ScopeTest.cs(12,15):error CS0136:A local variable named 'j' cannot be declared in this scope because it would give a difference
meaning to 'j',which is already used in a 'parent or current' scope to denote something else
其原因是:变量j 是在for循环开始定义的,在执行for循环时应处于其作用域内,在Main()方法结束执行后 变量j才超出作用域
第2个j(不合法)则在循环的作用域内,该作用域嵌套在Main()方法的作用域内 因为编译器无法区分这两个变量 所以不允许声明第2个变量
2字段和局部变量的作用域冲突
某些情况下 可以区分名称相同(尽管其完全限定的名称不同)作用域相同的两个标识符 此时编译器允许声明第2个变量
原因是C#变量之间有一个基本的区分 他把在类型级别声明的变量看做字段 把在方法中声明的变量看做局部变量
考虑下面的代码
虽然在Main()方法的作用域内声明了两个变量j,这段代码也会编译--在类级上定义的j 在该类删除前是不会超出作用域的
在本例中 当Main()方法中断 程序结束时,才会删除该类 以及在Main()中定义的j.此时 在Main()方法中声明的新变量j隐藏了同名的类级变量
所以在运行这段代码时,会显示数字30
但是如果要引用类级变量 该怎么办?可以使用语法object.fieldname 在对象的外部引用类或结构的字段 在上面的例子中 我们访问静态方法中的一个静态
字段(静态字段详见下一节)所以不能使用类的示例 只能使用类本身的名称
如果要访问一个实例字段(该字段属于类的一个特定实例),就需要使用this关键字
2.25 常量
顾名思义,常量是其值在使用过程中不会发生变化的变量 在声明和初始化时,在变量的前面加上关键字const 就可以把该变量指定为一个常量
const int a = 100; //This value cannot be changed
常量具有如下特点:
常量必须在声明时初始化 指定了其值后,就不能再改写了
常量的值必须能在编译时用于计算 因此 不能用从一个变量中提取的值来初始化常量
如果需要这么做 应使用只读字段(详见第3章)
常量总是静态的 但注意,不必实际上是不允许 在常量声明包含修饰符staitc
在程序中使用常量有3个好处
由于使用易于读取的名称(名称的值易于理解)替代了较难读取的数字或字符串,常量使程序变得更易于阅读
常量使程序更易于修改。例如,在C#程序中有一个SalesTax常量 该常量的值为6%.如果以后销售税率发生变化 把新值付给这个常量 这个可以修改所有
税款计算结果,而不必查找整个程序去修改税率为0.06的每个项
常量更容易避免程序出错 如果声明常量的位置以外的某个地方将另一个值付给常量 编译器就会报告错误
预定义数据类型
前面介绍了如何声明变量和常量,下面要详细讨论C#中可用的数据类型 与其他语言相比
C#对齐可用的类型及其蒂尼有更严格的描述
2.3.1 值类型和引用类型
在开始介绍C#中的数据类型之前 理解C#把数据类型分为两种非常重要
值类型
引用类型
下面几节详细介绍值类型和引用类型的语法 从概念上看 其区别是值类型直接存储其值
而引用类型存储对值的引用
这两种类型存储在内存的不同地方,值类型存储在堆栈中,而引用类型存储在托管堆上。注意
区分某个类型是值类型还是引用类型 因为这种存储位置的不同有不同的影响 例如 int是值类型 这表示下面的语句会在内存的两个地方存储值20
// i and j are both of type int
i = 20
j =i;
但考虑下面的代码 这段代码假定已经定义了一个类Vector Vector是一个引用类型 他有一个int类型的成员变量Value
要理解的重要一点是执行这段代码后,只有一个Vector对象 x和y都指向包含该对象的内存位置 因为x和y是引用类型的变量
声明这两个变量只保留了一个引用---而不会实例化给定类型的对象 两种情况下都不会真正创建对象 要创建对象就必须使用new关键字
如上所示。因为x和y引用同一个对象 所以对x的修改会影响y 反之亦然 因此上面的代码会显示30和50
C++开发人员应注意 这个语法类似于引用 而不是指针 我们使用句点符号 而不是->来访问对象成员。在语法上 C#引用看起来更类似于C++引用白能量
但是抛开表面的语法 实际上它类似于C++指针
如果变量是一个引用 就可以把其值设置为null 表示它不引用任何对象
y = null;
如果将引用设置为null,显然就不可能对它调用任何非静态的成员函数或字段,这么做会在运行期间抛出一个异常
在C#中,基本数据类型如bool和long 都是值类型。如果声明一个bool变量,并给它赋予另一个bool变量的值,在内存中就会有两个bool值
如果以后修改第一个bool变量的值,第二个bool变量的值也不会改变。这些类型是通过值来复制的
相反,大多数更复杂的C#数据类型,包括我们自己声明的类都是引用类型。它们分配在堆中,其生命期可以跨多个函数调用,可以通过一个或几个别名来访问
CLR执行一种精细的算法,来跟踪哪些引用变量仍是可以访问的,哪些引用变量已经不能访问了。CLR会定期删除不能访问的对象,把他们占用的内存返回给操作系统
这些通过垃圾收集器实现的
把基本类型(如int和bool)规定为值类型,而把包含许多字段的较大类型(通常在有类的情况下),规定为引用类型,C#设计这种方式的原因是可以得到最佳性能
如果要把自己的类型定义为值类型,就应把它声明为一个结构
2.3.2 CTS类型
如第1章所述,C#认可的基本预定义类型并没有内置于C#语言中,而是内置于.NET Framework中。例如,在C#中声明一个int类型的数据时
声明的实际上是.NET结构System.Int32的一个实例。这听起来似乎很深奥,但其意义深远:这表示在语法上,可以把所有的基本数据类型看做是支持某些方法的类
例如,要把int i转换为string,可以编写下面的代码
string s = i.ToString()
应强调的是,这种便利语法的背后,类型实际上仍存储为基本类型。基本类型在概念上用.NET结构表示 所以肯定没有性能损失
下面看看C#中定义的内置类型。我们将列出每个类型,以及它们的定义和对应.NET类型(CTS)的名称。C#有15个预定义类型 其中13个是值类型,两个引用类型
(string和object)
2.3.3 预定义的值类型
内置的CTS值类型表示基本类型,如整形和浮点类型,字符类型和布尔类型
1整型
C#支持8个预定义整数类型,如表2-1所示
名称 CTS类型 说明 范围
sbyte System.SByte 8位有符号的整数 -128~127
short System.Int16 16位有符号的整数 -32768~32767 -2^15 ~ 2^15-1
int System.Int32 32位有符号的整数 -2147483648 -2^32 ~2^31-1
long System.Int64 64位有符号的整数 -2^63 ~ 2^63 -1
byte System.Byte 8位无符号的整数 0~2^8-1
ushort System.UInt16 16位无符号的整数 0~65535(0~2^16-1)
uint System.UInt32 32位无符号的整数 0~2^32-1
ulong System.UInt64 64位无符号位的整数 0~2^64-1
一些C#类型的名称与C++和Java类型一致,但其定义不同 例如 在C#中 int总是32位带符号的整数 ,而在C++中 int是带符号的整数
但其位数取决于平台(在Windows上是32位)在C#中 所有数据类型都以与平台无关的方式定义 已被将来C#和.NET迁移到其他平台上
byte是0~255包括255的标准8位类型。注意在强调类型的安全性时,C#认为byte类型和char类型完全不同 它们之间的编程转换必须显示写出
还要注意,与整数的其他类型不同,byte类型在默认状态下是无符号的,其有符号的版本有一个特殊的名称sbyte
在.NET中 short不在很短 现在它有16位长。Int类型更长 有32位。long类型最长 有64位
所有整数类型的变量都能被赋予十进制或六进制的值 后者需要0x前缀
long x = 0x12ab;
如果对一个整数是int ,uint,long或是ulong没有任何显示的声明,则该变量默认为int类型
为了把输入的值指定为其他整数类型 可以在数字后面加上如下字符
uint ui=1234U;
long l =1234L;
ulong = ul = 1234UL;
也可以使用小写字母u和1,但后者会与整数1混淆
2 浮点类型
C#提供了许多整形数据类型 也支持浮点类型
float System.Single 32位单精度浮点数 7 范围 +- 1.5*10^-45 ~ 3.4 * 10^38
double System.Double 64位双精度浮点数 15/16 5.0*10-324 ~+- 1.710^308
flaot数据类型用于较小的浮点数 因为它要求的精度较低 double数据类型比float数据类型大,提供的精度也大一倍15位
如果再代码中没有对某个非整数值硬编码,则编译器一般假定该变量是doule 。如果想指定该值为float 可以在其后加上字符F或f
float f = 12.3F;
decimal类型
decimal类型表示精度更高的浮点数,如表2-3所示
decimal System.Decimal 128位高精度十进制数表示法 28 7.9*10^28
CTS和C#一个重要的有点是提供了一种专用类型进行财务计算 这就是decimal类型,使用
decimal类型提供的28位的方式取决于用户 换言之 可以用较大的精确度带有美分来表示较小的美元值 也可以在小数部分用更多的舍入来表示较大的美元值
但应注意,decimal类型不是基本类型 所以在计算式使用该类型会有性能损失
要把数字指定为decimal类型 而不是doule float或整形 可以在数字的后面加上字符M或m
decimal d = 12.30M
bool 类型
C#的bool类型用于包含布尔值true或false 如表2-4所示
bool System.Boolean 表示true或false NA true或false
bool值和整数值不能相互隐式转换。如果变量(或函数的返回类型)声明为bool类型,就只能使用值true或false 如果视图使用0 表示false
非0值表示true 就会出错
5 字符类型
为了保存单个字符的值 C#支持char数据类型 如表2-5所示
char System.Char 表示一个16位的UnitCode字符
char类型的字面量使用单引号括起来的 如'A'.如果把字符放在双引号中,编译器会把它看做字符串 从而产生错误
除了把char表示位字符字面量之外,还可以用4位十六进制的Unicode值(如'\u0041'),带有数据类型转换的整数值(如(char)65)或十六进制数
('\x0041')表示它们。它们还可以用转义序列表示,如表2-6所示
转义序列 字符
\' 单引号
\" 双引号
\\ 反斜杠
\0 空
\a 警告
\b 退格
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
预定义的引用类型
C#支持两种预定义的引用类型 如表2-7所示
object System.Object 根类型,CTS中的其他类型都是从它派生而来的 包括值类型
string System.String Unicode字符串
object类型
许多编程语言和类结构都提供了跟类型 层次结构中的其他对象都从它派生而来。C#和.NET也不例外。在C#中,object类型就是最终的父类型,所有内置类型和用户定义的
类型都从它派生而来 这样object类型就可以用于两个目的
可以使用Object引用绑定任何子类型的对象。例如 第7章将说明如何使用object类型把堆栈中的一个值对象装箱 在移动到堆中 。object引用也可以用于反射
此时必须有代码来处理类型未知的对象
object类型执行许多一般用途的基本方法 包括Equals()\GetHashCode() GetType()和ToString()
用户定义的类需要使用一种面向对象技术 重写 提供其中一些方法的替代执行代码 例如 重写ToString()时,需要提供一个方法 给出类本身的字符串表示
如果类中没有提供这些方法的实现代码
string 类型
C#有string关键字 在编译为.NET类时,它就是System.String 有了它 像字符串连接和字符串复制这样的操作就很简单了
string str1 = "Hello";
string str2 = "World";
string str3 = str1 + str2;//string concatenation
尽管这是一个值类型的赋值,但string是一个引用类型 String对象被分配在堆上 而不是栈上
因此 当把一个字符串变量赋值另一个字符串时,会得到对内存中同一个字符串的两个引用 但是string与引用类型在常见的操作上有一些区别
例如 字符串是不可改变的 修改其中一个字符串 就会创建一个全新的string对象 而另一个字符串不发生任何变化 考虑下面的代码
s1 is a string
s2 is a string
s1 is now another string
s2 is now a string
改变了s1的值对s2没有影响,这与我们期待的引用类型正好相反。当用值"a string"初始化s1时,就在堆上分配了一个新的string对象。在初始化s2时
引用也指向这个对象,所以s2的值也是"a string".但是当现在要改变s1的值时,并不会替换原来的值,堆上会为新值分配一个新的对象 s2变量扔指向原来的对象
所以他的值没有改变。这实际上是运算符重载的结果
基本上,string类实现为其语义遵循一般的、直观的字符串规则
字符串字面量放在双引号中("...");如果试图把字符串放在单引号中,编译器就会把它当做char从而印发错误 C#字符串和char一样,可以包含Unicode和十六进制数
转义序列。因为这些转义序列以一个反斜杠开头,所以不能再字符串中使用这个非转义的反斜杠字符 而需要用两个反斜杠字符(\\)来表示它
string filepath = "C:\\ProCSharp\\First.cs";
即使用户相信自己可以再任何情况下都记住要这么做,但输入两个反斜杠字符会令人迷惑,幸好,C#提供了另一种替代方式
可以再字符串字面量的前面加上字符@;在这个字符后的所有字符都看做是原来的含义 它们不会解释为转义字符
string filepath = @"\F:\每一天\20220106\ConsoleApp1\ConsoleApp1\核心.cs";
甚至允许在字符串字面量中包含换行符:
'Twas brilling and the slithy toves
Did gyre and gimble in the wabe’
*/
#endregion
#region 2.4 流控制
/*本章将介绍C#语言的重要语句"控制程序流的语句,它们不是按代码在程序中的排列位置顺序执行的
2.4.1 条件语句
条件语句可以根据条件是否满足或根据表达式的值控制代码的执行分支。C#有两个控制代码分支的结构
if语句 测试特定条件是否满足 switch语句 它比较表达式和多个不同的值
1if语句
对于条件分支 C#继承了C和C++的if...else结构 对于用过语言编程的人 其语法非常直观
if(condition) statement(s)
else
statements(s)
如果在条件中要执行多个语句 就需要用花括号({})把这些语句组合为一个块(这也适用于其他可以把语句组合为一个块的C#结构,如for和while循环)
i is Zero
i is Non-zero
i is Non-zero
i is Non-zero
i is Non-zero
还可以单独使用if语句 不加最后的else语句 也可以合并else if子句 测试多个条件
Type in a string
test
The string has less than 5 characters
The string was test
添加到if 子句中的else if语句的个数不受限制
注意在上面的例子中 我们声明了一个字符串变量Input,让用户在命令行输入文本 把文本填充到input中 然后测试该字符串变量的长度
代码还说明了在C#中如何进行字符串处理。例如要确定input的长度 可以使用input.Length
对于if ,要注意的一点是如果条件分支中只有一条语句 就无须使用花括号
Type in a string
You typed in an empty string.
The string was
i can be anything
但是,为了保持一致,许多程序员只要使用if语句 就加上花括号
前面介绍的if语句还演示了用于比较数值的一些C#运算符,特别注意,C#使用"==“对变量进行等于比较
此时不要使用”=".一个"="用于赋值
在C#中 if 子句中的表达式必须等于布尔值。不能直接测试整数(如从函数中返回的值)
而必须明确的把返回的整数转换为true或false 例如将值与0或null进行比较
2 swich语句
switch...case 语句适合于从一组互斥的分支中选择一个执行分支。其形式是switch参数的后面跟一组case子句
如果switch参数中表达式的值等于某个case子句旁边的某个值 就执行case子句中的代码
此时不需要使用花括号把语句组合到块中;只需使用break语句表计每段case代码的结尾即可。也可以在switch语句中包含
一条default子句 如果表达式不等于任何case子句的值,就执行default子句的代码 下面的switch语句测试integerA变量的值
switch (integerA)
{
case 1:
Console.WriteLine("integer =1");
break;
case 2:
Console.WriteLine("integerA =2");
break;
case 3:
Console.WriteLine("integerA =3");
break;
default:
Console.WriteLine("integerA is not 1,2,or 3");
break;
}
注意case的值必须是常量表达式;不允许使用变量
C和C++程序员应很熟悉switch...case语句 而C#的
#region MyRegion
// string filepath = @"\F:\每一天\20220106\ConsoleApp1\ConsoleApp1\核心.cs";
// string jsbberwocky = @"'Twas brilling and the slithy toves
//Did gyre and gimble in the wabe'";
// Console.WriteLine(jsbberwocky);
//bool isZero;
//for (int i = 0; i < 5; i++)
//{
// if (i == 0)
// {
// isZero = true;
// Console.WriteLine("i is Zero");
// }
// else
// {
// isZero = false;
// Console.WriteLine("i is Non-zero");
// }
//}
//Console.WriteLine("Type in a string");
//string input;
//input = Console.ReadLine();
//if (input == "")
//{
// Console.WriteLine("You typed in an empty string.");
//}
//else if (input.Length < 5)
//{
// Console.WriteLine("The string has less than 5 characters");
//}
//else if (input.Length < 10)
//{
// Console.WriteLine("The string had at least 5 but less than 10 " +
// "Characters.");
//}
//if(input.Length == 0) //Let's add some brackets here
//Console.WriteLine("The string was " + input);//This will only execute if i ==0
//Console.WriteLine("i can be anything"); //Will execute whatever the value of i
//if (DoSomething() != 0)
//{
// //Non-zer value returned
//}
//else
//{
// //Returned zero
//}
//int integerA =1;
//switch (integerA)
//{
// case 1:
// Console.WriteLine("integer =1");
// break;
// case 2:
// Console.WriteLine("integerA =2");
// break;
// case 3:
// Console.WriteLine("integerA =3");
// break;
// default:
// Console.WriteLine("integerA is not 1,2,or 3");
// break;
//}
这段代码说明了如何从字符串获取枚举值,并转换为整数。要从字符串中转换,需要使用静态的Enum.Parse()方法
这个方法带3个参数。第1个参数是要使用的枚举类型 其语法是关键字typeof后跟放在括号中枚举类名 typeof运算符
第2个参数是要转换的字符串 第3个参数是一个bool 执行在进行转换时是否忽略大小写 最后 注意Enum.Parse()方法实际上
返回一个对象引用我们需要把这个字符串显示转换为需要的枚举类型 这是一个拆箱操作的例子
上面代码 返回1 作为一个对象 对应于TimeOfDay.Afternoon的枚举值 在显示转换为int 会字词生成1
#endregion
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 CS0017 程序定义了多个入口点。使用 /main (指定包含入口点的类型)进行编译。 ConsoleApp1 F:\每一天\20220106\ConsoleApp1\ConsoleApp1\Program.cs 18 活动
F:\每一天\20220106\ConsoleApp1\ConsoleApp1\bin\Debug>ConsoleApp1.exe ArgsExample /a /b /c
ArgsExample
/a
/b
/c
*/
#endregion
}
}