C#基础知识回顾(第一部分 共四部分)
第1章 概述
1.1 Microsoft.NET Framework
Microsoft.NET Framework(简称.NET框架)是生成和运行.NET应用程序和Web Service的组件库
1.1.1 .NET框架的关键实体
- 公共语言运行时(CLR):提供.NET应用程序所需要的核心服务
- 公共类型系统(CTS):是一个正式的规范,规定了类型必须要如何定义才能被CLR承载
- 公共语言规范(CLS):一套规则,描述了支持.NET的编译器必须支持的最小的和完全的特征集,以生成由CLR承载的代码
公共语言运行时(CLR)
使用.NET提供的编译器可以直接将源程序编译为.EXE或者.DLL文件,但是编译出来的程序代码并不是CPU能直接执行的机器代码,而是一种中间语言(IL: Intermediate Language)代码
使用中间语言代码:(1)可以实现平台无关性,即与特定的CPU无关;(2)可以实现不同语言之间的交互
1.1.2 基类库(BCL)
提供开发和运行.NET应用程序的支持
- 类库(Class Library)是一个与公共语言运行库紧密集成的可重用的类的集合
- 类库提供了Internet和企业级开发所需要的各种功能,完全支持Web标准及其应用,而且使用简单,扩充方便
- 类库分配到不同的命名空间下
1.1.3 .NET框架的特点
一种框架,多种语言
.NET框架支持的语言有:除了基于.NET框架的C#语言、VB.NET语言、C++.NET语言以及和Java语言语法完全相同的J#语言外,还有基于.NET框架的FORTRAN语言、Pascal语言、COBOL语言、PERL语言、R语言、Python语言和Eiffel语言等其他高级语言
1.2 C#应用程序的结构
每一个用C#语言编写的应用程序均由一个或者多个类组成,所有的程序代码都必须封装在某个类、结构、枚举、委托或者接口中
一个应用程序由一个或者多个类组成,任何一个程序功能都必须封装在某个类中
一个应用程序可以由一个文件组成,也可以有多个文件组成,文件名可以和类名相同,也可以不同(建议命名相同)
C#源程序文件的扩展名为.cs,一个源文件中可以有一个类,也可以有多个类,每个应用程序必须有一个入口点,入口方法名规定为Main(Main方法的返回值类型只能是void或int)
类中的每一个方法都要有一个返回值,对于没有返回值的方法,可以声明返回值为void
1.2.1 命名空间
命名空间:是对类的一种划分形式,类似于目录和文件的划分形式,也是一种逻辑划分,而非物理上的存储分类
调用方法:
命名空间.命名空间….命名空间.类名.静态方法名(参数,…);
命名空间.命名空间….命名空间.类实例名. 方法名(参数,…);
例如:System.Console.WritleLine(”Hello World!”);
1.2.2 using关键字
(1)指定引用的命名空间,例如:
using System.Windows.Forms;
(2)简化命名空间的层次表达形式,例如:
using WinForm=System.Windows.Form;
(3)作为语句,定义一个范围。例如:
Font font1 = new Font(“Arial”, 10.0f); using (font1) {… }
程序执行到“}”时,就会自动释放font1对象。
1.2.3 Main方法
- 每个应用程序必须有一个入口点,入口方法名规定为Main,并且Main后边的小括号不能省略
- Main方法声明为public static,除非有特殊理由,一般不要更改Main方法的声明,且方法的返回值只能是void或者int
- Main方法可以放在任何一个类中。一个应用程序中必须有一个类包含Main方法
几点重要的说明
使用using关键字指明引用的命名空间,使用namespace关键字声明命名空间,使用class关键字声明类,类中包含了程序所要用到的数据和所要执行的方法的定义
1.3 编程调试
1.3.1 断点设置与程序调试
断点设置
-
单击某代码行左边的灰色区域,单击设置,再次单击取消设置
-
鼠标右击某代码行,选择【断点】->【插入断点】或者【删除断点】
-
单击某代码行,直接按键进行设置或取消设置
利用断点调试程序
按执行到断点,再按到下一断点,
……
按+键终止调,逐过程,逐语句
1.3.2 C#代码编写命名建议
匈牙利命名法:匈牙利命名法是一种编程时的命名规范。基本原则是:变量名=类型+对象描述,其中每一对象的名称都要求有明确含义,可以取对象名字全称或名字的一部分
第2章 C#语法基础
2.1 数据类型
C#数据类型分为两类:值类型和引用类型
值类型:包括简单类型、枚举类型、结构类型、可空类型
引用类型:包括类、接口、数组、委托
一般把引用类型的变量称为对象
值类型与引用类型的区别:
特性 | 值类型 | 引用类型 |
---|---|---|
变量中保存的内容 | 实际数据 | 指向实际数据的引用指针 |
内存空间配置 | 栈(Stack) | 受管制的堆(Managed Heap) |
内存需求 | 较少 | 较多 |
执行效率 | 较快 | 较慢 |
内存释放时间点 | 执行超过定义变量的作用域时 | 由垃圾回收机制负责回收 |
可以为null | 不可以 | 可以 |
2.2 不同数据类型之间的转换
有两种转换方式:隐式转换与显示转换,若是不同值类型之间的转换,可以使用Convert类
2.2.1 隐式转换与显示转换
隐式转换
从低精度、小范围的数据类型转换为高精度、大范围的数据类型,可以用隐式转换
int k = 1; long i = 2; i = k; //隐式转换
显示转换
也称为强制转换,用户必须明确地指定转换的类型(所有的隐式转换也都可以采用显示转换的形式来表示)
将大范围类型的数据转换为小范围类型的数据的时候,属于显式转换,另外还必须特别谨慎,因为此时有丢失数据的危险
2.2.2 装箱与拆箱
Object类型:所有其他引用类型的基类
装箱:将值类型转换为object类型(int i = 32;object o = i;)
拆箱:显式地将object类型转换为值类型(int i = 123;object box = i;int k = (int)box)
装箱,就是把值类型转换成引用类型,在托管堆上建一个新对象,并把指定类型的值付给他。拆箱则相反,把托管堆上的引用类型的值赋给堆栈上的值类型变量
2.3 常量与变量
2.3.1 C#中提供2种类型的常量
使用const关键字声明
const常量是在编译时设置其值并且永远不能更改其值的字段,在对程序进行编译的时候,编译器会把所有const常量全部替换为常数
const int PI=3.14;
使用readonly关键字声明
readonly关键字在程序运行期间只能初始化“一次”的字段,可以在声明语句中初始化该字段,也可以在构造函数中初始化该字段。初始化以后,用readonly声明的字段的值就不能再更改
注意:二者区别为readonly常量运行时初始化,const常量编译时初始化,const常量只能在声明中赋值,readonly常量既可以在声明中赋值,也可以在构造函数中赋值
2.3.2 变量
变量用来表示一个数值、一个字符串值或者一个类的对象,变量存储的值可能会发生更改,但变量名称保持不变,C#定义了7类变量,分别是:静态变量、实例变量、数组元素、值参数、引用参数、输出参数和局部变量
匿名类型的变量
匿名类型的变量就是程序员不必指定“局部”变量的类型,统统用var来表示类型即可,在LINQ表达式或者foreach语句中,使用匿名类型的变量比较方便,匿名类型仍然属于强类型,只不过判断具体类型的工作由编译器完成
2.4 控制台应用程序与格式化输出
2.4.1 控制台输入输出
控制台输出:
Console.Write ():把各种类型的数据或对象转换成字符串写入标准输出流
Console.WriteLine():把各种类型的数据或对象转换成字符串写入标准输出流,与Write的区别在于,它还输出回车符和换行符(“\r\n”)
控制台输入:
Console.ReadKey():标准输入流读取用户按下的字符或功能键
ConsoleKeyInfo c=Console.ReadKey()
Console.ReadLine():从标准输入流读取一行字符
2.4.2 字符串的格式化输出
字符串格式化:Console类的Write或WriteLine方法,String.Format方法中均可以规定输出字符串的格式
格式输出的一般形式为 {N [, M] [: 格式码]}(其中,[ ]表示其中的内容为可选项)
N:从零开始的整数,表示第几个参数
M:可选整数,表示最小长度。若参数N的长度小于M,就用空格填充。如果M为负,则左对齐;如果M为正,则右对齐;如果未指定M,则默认为零
0占位符与#占位符
0 | 0占位符,如果数字位数不够指定的占位符位数,则左边补0至占位符位数;如果数字位数超过指定的占位符位数,则按照原数字实际位数原样输出。如果小数部分的位数超出指定的占位符位数,则多余的部分四舍五入。 | Console.WriteLine("{0:00000}", 123);Console.WriteLine("{0:000}", 12345);Console.WriteLine("{0:0000}", 123.64);Console.WriteLine("{0:00.00}", 123.6484); | 00123 12345 0124 123.65 |
---|---|---|---|
# | #占位符。对整数部分,去掉数字左边的无效0;对小数部分,按照四舍五入原则处理后,再去掉右边的无效0。如果这个数就是0,而又不想让它显示的时候,#占位符很有用 | Console.WriteLine("{0:####}", 123);Console.WriteLine("{0:####}", 123.64);Console.WriteLine("{0:####.###}", 123.64);Console.WriteLine("{0:####.##}", 0);Console.WriteLine("{0:####.##}", 123.648); | 123 124 123.64 123.65 |
对于字符串来说,可以直接利用格式化输出得到希望的格式
string s = string.Format(“{0, 30}”, ‘ ’);
//s得到的结果为30个空格的字符串,左边补空格
string s1 = string.Format(“{0, -20}”, “15”);
//s1得到的结果为左对齐长度为20的字符串,右边补空格
利用string.Format方法格式化字符串:
int i = 123;
string s1 = string.Format("{0:d6}", i);
string s2 = $"{i:d6}";
//结果:s1=000123,s2=000123
Console.WriteLine("s1="+s1+",s2="+s2);
2.4.3 数字的格式化输出
常用格式举例:
string s = string.Format("{0:d6}", 123); //s得到的结果为000123,6位十进制左对齐输出,且采用0占位
string s2 = string.Format("i:{0,-7}, j:{1,7}", i, j); //占七位但不用0占位,一个左对齐一个右对齐
补充:
2.4.4 日期和时间的格式化输出
DateTime dt = new DateTime(2006,5,25);
// yy(yyyy)表示年占两(四)位,M表示月占1位,超出1位按实际位数,d表示日占1位,超出1位按实际位数
string str = dt.ToString(“yy.M.d”);
第3章 常用数据类型的用法
3.1 字符串
字符串的创建与表示形式:
通过String类创建字符串
string myString = "some text";
string s2 = new string('a',2); //结果为aa
字符串查找:
- Contains方法:用于查找一个字符串中是否包含指定的子字符串
//public bool Contains( string value )
string str1 = "this is a string.";
bool b=str1.Contains("is" );
- IndexOf方法:求某个字符或者子串在字符串中出现的位置
public int IndexOf(string s )
public int IndexOf(string s, int startIndex )
-
LastIndexOf方法:LastIndexOf方法的用法与IndexOf方法相同,查找最后一次出现的位置
-
StartsWith方法和EndsWith方法:从字符串的首或尾开始查找指定的子字符串,并返回布尔值(true或false)
-
IndexOfAny方法:查找某个字符串中是否包含某些字符(多个不同的字符)
返回数组中任何一个字符最早出现的下标位置,索引仍然是从‘0’开始
- 求子字符串
Substring(int startIndex) //截取从startIndex开始到字符串结尾的字符串
Substring(int startIndex,int count) //截取字符串从startIndex位开始,截取长度为count的字符串
字符串的插入、删除和替换:
-
插入字符串:public string Insert(int startIndex,string value)
-
删除字符串:Remove(int startIndex)//删除从startIndex到字符串结尾的子字符串,Remove(int startIndex,int count) //删除从startIndex开始的count个字
-
字符串替换:Replace (string oldStr,string newStr) ,
移除首尾特定的字符:
- 从字符串开头或结尾删除指定的字符:利用TrimStart删除字符串首部字符,利用TrimEnd删除字符串尾部字符,利用Trim删除字符串首部和尾部字符(默认移除空格)
字符串的合并与拆分:
- Join方法:在数组的每个元素之间串联指定的分隔符,从而产生单个串联的字符串
public static string Join( string separator, string[ ] value )
- Split方法:将字符串按照指定的一个或多个字符进行分离,从而得到一个字符串数组
public string[ ] Split( params char[ ] separator )
Join与Split:
string[ ] sArray1 = { "123", "456", "abc" };
string s1 = string.Join(",", sArray1); //结果为"123,456,abc"
string[ ] sArray2 = s1.Split(','); //sArray2得到的结果与sArray1相同
string s2 = "abc 12;34,56";
string[ ] sArray3 = s2.Split(',', ';', ' '); //分隔符为逗号、分号等
字符串中字母大小写的转换:
ToUpper方法与ToLower方法
String和StringBuilder:
- String类实际上表示的是一系列不可变的字符。说其实例是“不可变的”,是因为无法直接修改给该字符串分配的堆中的字符串
例如,在myString的后面接上另一个字符串:myString += " and a bit more";
其实际操作并不是在原来myString所占内存空间的后面直接附加上第二个字符串,而是返回一个新String实例,即重新为新字符串分配内存空间
- StringBuilder类位于System.Text名称空间下,使用StringBuilder类每次重新生成新字符串时不是再生成一个新实例,而是直接在原来字符串占用的内存空间上进行处理,而且它可以动态的分配占用的内存空间大小
StringBuilder的常用方法:
Append()追加字符串;AppendFormat():追加格式化字符串;Remo(int startIndex,int length):移除字符串;ToString():转化为字符串String类型
3.2 数组
数组的特点:1.存储同一种类型的数据;2.一种引用类型,而非值类型;3.数组是按数组名、数据元素的类型和维数来描述;4.一维数组、多维数组、交错数组
3.2.1 数组的声明与初始化
声明数组时,既可以一开始就指定数组元素的个数,也可以一开始不指定元素个数,而是在使用数组元素前动态地指定元素个数
int[] a = new int[30];
int[] b;
String[] mString = {"first","second","third"};
数组类型 | 语法 | 例子 |
---|---|---|
一维数组 | 数据类型[ ] 数组变量; | int[] myArray; |
二维数组 | 数据类型[,] 数组变量; | int[,] myArray; |
三维数组 | 数据类型[,] 数组变量; | int[,] myArray; |
交错数组 | 数据类型[][] 数组变量; | int[][] myArray; |
3.2.2 数组的秩与数组长度
数组的秩(rank)是指数组的维数,例如一维数组秩为1,二维数组秩为2
数组长度是指数组中所有元素的个数。例如:
int[ ] a = new int[10]; //数组长度为10
int[,] b = new int[3, 5]; //数组长度为3*5=15,其中第0维长度为3,第1维长度为5
Array类提供访问秩和长度的属性和方法
(1)Rank属性
(2)Length属性
(3)GetLength(i) 获取数组某一维的长度
交错数组:
交错数组相当于一维数组的每一个元素又是一个数组,也可以把交错数组称为**“数组的数组”**
int[ ][ ] n1 = new int[2][ ]
{
new int[ ] {2,4,6},
new int[ ] {1,3,5,7,9}
};
交错数组的每一个元素既可以是一个一维数组,也可以是多维数组
交错数组元素的为访问:
int[,][,] jarray = new int[,][,]
{
{
new int[2, 3] { { 1, 2, 3 }, { 2, 3, 4 } },
new int[1, 2] { { 1, 2 } }
},
{
new int[1, 3] { { 1, 2, 3 } },
new int[3, 2] { { 2, 3 }, { 22, 12 }, { 32, 2 } }
}
};
jarray[0, 0][0, 1] = 12;
Console.WriteLine(jarray[1, 1][2, 1]);
动态改变数组的大小:
Resize方法:public static void Resize( ref T[ ] array, int newSize )
这是一种泛型表示形式。其中T表示数组类型,array为要调整大小的一维数组,该数组从零开始;如果为null则新建具有指定大小的数组。如果newSize大于旧数组的Length,则分配一个新数组,并将所有元素从旧数组复制到新数组。如果newSize小于旧数组的Length,则分配一个新数组,并将元素从旧数组复制到新数组直到新数组被填满为止;旧数组中的剩余元素将被忽略。如果 newSize与旧数组的 Length相等,则此方法不执行任何操作
数组元素的排序与查找:
C#语言中还提供了Sort和Reverse这样的静态方法,这些方法用快速排序算法将一维数组中的元素按照升序或降序排列。还可以方便地查找指定的元素。例如Contains方法和IndexOf方法等
数组的统计以及数组和字符串之间的转换:
- 数组的统计:利用数组的Average方法、Sum方法、Max方法和Min方法可以求数组中所有元素的平均值、求所有元素的和、最大值和最小值
- 对于字符串数组,可以直接利用字符串的Join方法和Split方法实现字符串和字符串数组之间的转换(Join通过分隔符将数组转化为字符串,Split则是将通过特定分隔符字符串转换为数组)
3.3 枚举
枚举(enum)是一组命名常量的集合,称为枚举成员列表。它可以为一组在逻辑上密不可分的整数值提供便于记忆的符号,从而使代码更清晰,也易于维护
枚举是值类型,其类型可以是:byte、sbyte、short、ushort、int、uint、long、ulong,如果没有指定类型,则默认为 int 类型,且枚举类型区分大小
声明enum类型变量的语法为:[附加声明] [访问修饰符] enum 名称[:数据类型]{ 枚举列表}
enum days{Mon,Tue,Wed,Thu,Fri,Sat}
注意:默认情况下,第一个枚举数的值为 0,后面每个枚举数的值在前一个枚举数的值基础上递增1
虽然枚举有类型,但取枚举数的值时,仍然需要进行类型转换
枚举可以与类平级,也可以作为类的 field,但不能放在函数中。可以加 public 等修饰符
enum FirstEnum { Mem1, Mem2 }
enum SecondEnum { Mem1, Mem2 }
class Program
{
static void Main(string[] args)
{
if (FirstEnum.Mem1 < FirstEnum.Mem2)
Console.WriteLine("First");
if(FirstEnum.Mem1<SecondEnum.Mem2)
Console.WriteLine(“Second”);
}
}
Enum结构:GetNames 检索指定枚举中常数名称的数组 ;GetName 在指定枚举中检索具有指定值的常数的名称;GetValues 检索指定枚举中常数值的数组
3.4 日期与事件处理
对日期和时间处理的常用类是DateTime类和TimeSpan类
- DateTime类表示范围在0001年1月1日午夜12:00:00到9999年12月31日晚上11:59:59之间的日期和时间,最小时间单位等于100纳秒
- TimeSpan类表示一个时间间隔。其范围在Int64.MinValue到Int64.MaxValue之间
3.4.1 DateTime类常用方法和属性
静态方法和属性:
DateTime.Now;DateTime.Today;
DateTime.Compare(DateTime dt1,DateTime dt2); //对两个DateTime实例进行比较,并返回一个指示第一个实例是早于、等于还是晚于第二个实例的整数
DateTime.Parse(string str) //使用当前线程区域性的约定将日期和时间的字符串表示形式转换为其等效的DateTime
实例方法和属性:
(假设dt为DateTime的一个实例)
dt.Day,dt.Month,dt.Year,dt.Hour…
dt.ToLongDateString(),dt.ToShortDateString()
dt.ToString(“yyyy-mm-dd”)//多种形式
dt.CompareTo(DateTime dt1)//与一个DateTime实例进行比较,并返回一个指示早于、等于还是晚于这个实例的整数
3.5 数学运算
Math类位于System命名空间下,为三角函数、对数函数和其他通用数学函数提供常数和静态方法
int i = 10, j = -5;
double x = 1.3, y = 2.7;
double a = 2.0, b = 5.0;
Console.WriteLine(string.Format("-5的绝对值为{0}", Math.Abs(j)));
Console.WriteLine(string.Format("大于等于1.3的最小整数为{0}", Math.Ceiling(x)));
Console.WriteLine(string.Format("小于等于2.7的最大整数为{0}", Math.Floor(y)));
Console.WriteLine(string.Format("10和-5的较大者为{0}", Math.Max(i, j)));
Console.WriteLine(string.Format("1.3和2.7的较小者为{0}", Math.Min(x, y)));
Console.WriteLine(string.Format("2的5次方为{0}", Math.Pow(a, b)));
Console.WriteLine(string.Format("1.3的四舍五入值为{0}", Math.Round(x)));
Console.WriteLine(string.Format("5的平方根为{0}", Math.Sqrt(b)));
Console.ReadLine();
}
}
}
3.6 随机数
Random类用于生成随机数
默认情况下,Random类的无参数构造函数使用系统时钟生成其种子值,而参数化构造函数可根据当前时间的刻度数采用Int32值
使用
Random r = new Random( );
int i=r.Next(10);
double d = r.NextDouble();//返回0.0~1.0之间的随机数
如果文章对您有所帮助,记得一键三连支持一下哦~