.net学习笔记-C#语言基础篇1
一、交换两个数据的值 交换两个数据的值,可以通过使用中间变量,也可以不使用中间变量
1.使用中间变量
1 int num1,nun2,temp; 2 num1=1; 3 num2=2; 4 Console.WriteLine("num1={0},num2={1}",num1,num2);//交换前 5 temp=num1; 6 num1=num2; 7 num2=temp; 8 Console.WriteLine("num1={0},num2={1}",num1,num2);//交换后
2.不使用中间变量
1 int num1,num2;//定义两个数 2 num1=1; 3 num2=2; 4 Console.WriteLine("num1={0},num2={1}",num1,num2);//先输出交换前num1,num2 5 num1=num1+num2; 6 num2=num1-num2; 7 num1=num1-num2; 8 Console.WriteLine("num1={0},num2={1}",num1,num2);//输出交换后的num1,num2
二、定义方法:
访问修饰符 返回值类型 方法名称(参数){方法体}
1. 访问修饰符:public private protected internal
a) public :使用它来定义的成员可以在所有类里面使用(不同项目需要先引用)
b) private:私有的,只有在当前类中可以使用
c) protected:使用它来定义的成员只有在当前类或者当前类的子类中使用。
d) internal:在当前整个程序集中可以使用
2. 返回值类型
a) void:没有返回值.(可以写return(可以提前终止方法),但是不能return具体的值)
b) 非void,必须返回相应类型的值(任何类型都可以做为方法的返回值类型)
3. 方法名称:
a) Pascal命名法,每一个单词的首字母需要大写
b) 不能使用关键字(int double bool string …..class namespace)
c) 不能包含_以外的特殊符号,不能以数字开头 java(_ $)
4. 参数
a) 形参:只是一个参数的声明,说明调用的时候需要传递过来的值(类型一致,个数一致,顺序一致)---形参是实参的规范。
三、静态成员与非静态成员之间的调用方式:
1. 在单个类中:静态成员不能直接调用非静态成员(属性,方法),只能通过实例化后的对象调用。
2. 在单个类中:静态成员可以直接调用静态成员
3. 在单个类中:实例成员可以自由调用静态成员
4. 在不同类中:实例成员通过类的对象调用,而静态成员通过类名调用。
5. 为什么静态不能直接调用非静态成员:运行时静态成员与类一起加载(已经存在),在加载静态成员的时候,非静态成员还没有实例化(还没有存在)。
四、C#的Main方法的四种形式:
1. static void Main(string[] args);
2. static void Main();
3. static int Main(string[] args);
4. static int Main(s);
五:可变参数:params:它是一个数组类型的变量。会自动根据用户传递的值生成一个数组(注意传递的值需要同一类型。)
1. 可以根据需要传递0 个或者多个参数。
2. 如果没有传递任何参数,需要做一个判断,不然可能造成索引越界的错误。
3.在参数列表中必须是在最后的位置。
六、代码规范:
1. 注释:
a) // 单行注释
b) /**/:多行注释
c) ///文档注释:可以生成提示
2.变量命名:camel:第一个单词首字母小写,后面每一个单词的首字母大写
3.对于类和方法:每一个单词首字母都要大写。
4.代码需要缩进与对齐。
注意:
1.在企事业里面可能这有这样的建议:规定所有自定义变量都使用 _ 开头
2.变量的名称一般是名词:说明这个变量代表的意义
3.方法:一般是动词,说明这个方法可以执行的具体操作
4.在定义变量的时候,长短不是关键,意义才是关键,不要怕麻烦
七、数组:所有存储结构中效率最高,因为它在内存中是一串连续的存储空间
1. 如何定义:类型[] 名称=new int[长度];
2. 数组里面只能存储同一类型的值
3. 在c#中,[]只能写在类型后面
4. 一般需要确定长度或者值,可以同时指定,但是长度与值的数量需要对应。
5. 因为数组长度固定,所以对数组的操作一般可以考虑使用for循环结构!
6. 数组元素的添加:
int[] arrScore = new int[5]{1,2,3,4,5}; arrScore[0]=1;//如果只为其中某一些下标对应的数组元素赋值那么其它的就会有默认值。 for (int i = 0; i < arrScore.Length; i++) { arrScore[i]=值; }
7. 数组元素的修改:通过索引
ArrScore[i]=值;
8. 数组元素的遍历:
for (int i = 0; i < arrScore.Length; i++) { if(arrScore[i]!=null) //对于引用类型对象数组才有用(string) { } Console.WriteLine(arrScore[i]); }
9. 数组元素的删除:
//1.先确定需要删除的元素的位置(下标索引)--需要循环遍历 for (int i = 0; i < arrScore.Length; i++) { if(arrScore[i]==num) { position = i; } } Console.WriteLine("position:"+position); //2.将这个值以后的所有值都往前面移动一位: arr[i] = arr[i + 1];//需要注意索引是否越界 for (int i = position; i < arrScore.Length-1;i++ ) { arrScore[i] = arrScore[i + 1]; //将后面的元素值覆盖前面元素值 } //3.清空最后一个值:注意不同数组类型的默认值,这里因 整型数组的默认是0.所以这里只是清空到0 arrScore[arrScore.Length - 1] = 0;
八、在排好序的数组(由小到大)中插入一个数值,插入后数组仍是原来的排序
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 数组_插值 { class Program { static void Main(string[] args) { int[] arr=new int[]{3,34,54,86,100};//定义一个已经排好序的整型数组 for(int i=0;i<arr.Length;i++)//遍历输出数组 { Console.Write(arr[i]+" "); } Console.WriteLine("\r\n请输入要插入的数值:"); int insertNum = int.Parse(Console.ReadLine()); //Console.WriteLine("请输入在哪个数值前插入:"); //int num = int.Parse(Console.ReadLine()); arr = InsertNum(arr,insertNum); for (int i = 0; i < arr.Length; i++)//遍历输出新数组 { Console.Write(arr[i]+" "); } Console.ReadKey(); } #region 插入一个数值到已排好序的数组-static int[] InsertNum(int[] arr, int insertNum) /// <summary> /// 插入一个数值到已排好序的数组 /// </summary> /// <param name="arr">排好序的数组</param> /// <param name="insertNum">要插入的数据</param> /// <returns></returns> static int[] InsertNum(int[] arr, int insertNum) { int positionIndex = -1;//定义插入的位置 for (int i = 0; i < arr.Length; i++)//获取需要插入的位置 { if (insertNum < arr[i]) { positionIndex = i; break; } else { positionIndex = arr.Length; } } int[] newArr = new int[arr.Length + 1];//定义新数组并实例化 arr.CopyTo(newArr, 0);//为新数组赋值 for (int i = newArr.Length - 1; i > positionIndex; i--) { newArr[i] = newArr[i - 1]; } newArr[positionIndex] = insertNum;//把数值插入 return newArr; } #endregion } }
九、二维数组和交错数组
1. 二维数组
a) 定义:int[,] arr=new int[3,4];//必须指定二个维度的值
b) 遍历:通过getLength(维度)取得某维度的长度值:代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
for (int i = 0; i < twoDArr.GetLength(0);i++ ) { for (int j = 0; j < twoDArr.GetLength(1);j++ ) { Console.Write(twoDArr[i,j]+" "); } Console.WriteLine(); }
2. 交错数组
a) 交错数组的本质就是一个一维数组,只不过这个数组里面的每一个元素值又是一个数组
b) 交错数组的元素需要先实例化,因为数组是一个引用类型的变量,需要先实例化再使用,如果没有实例化会出现 “未将对象引用设置到对象的实例”的错误
c) 因为交错数组的每一个元素类型是数组,所以遍历的时候就可以按遍历一维数组的方式考虑,代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
int[][] arr=new int[2][];//一个存储有两个数组元素的数组 //数组的每个元素又是一个数组对象,所以需要先实例化数组对象 arr[0] = new int[] { 1, 2, 3 }; arr[1] = new int[] { 1, 2, 3,4,5,6,7,8,9 }; for (int i = 0; i < arr.Length;i++ ) { for (int j = 0; j < arr[i].Length;j++ ) { Console.Write(arr[i][j]+" "); } Console.WriteLine(); }
十、return:
1. 可以返回一个变量---当方法有返回值类型的时候
2. 还可以中止当前方法
3. 如果在异常处理结构里面,不管是否之前运行到return,finally的代码都会被执行。
十一、变量的作用域:
1. 全局变量(成员变量)
2. 局部变量:在方法体内定义的变量---作用域只是在方法体内,出了方法体就不能再使用,如果一定需要使用,有三个方法:
a) 可以做为参数传递
b) 还可以做为返回值
c) 还可以做成类的成员变量---静态成员变量不是很安全
十二、方法重载:系统会根据调用方法传递的实参来自动匹配拥有相应形参的方法。
1. 方法名称一致,但是方法的参数列表不一致(参数的类型不一致,参数的数量不一致),只要满足其中一个就构成重载的条件(如果两个都满足那一定构成重载的条件)--与方法的返回值无关。
2. 这里的方法重载是指同一个类中方法重名,参数列表不一致的情况。
3. 作用:同一个名称,多种响应结果(与你的参数列表有关系),解决了命名烦恼。
十三、普通的值传递和ref传递参数:
1. 普通的值做为参数传递的时候,传递的其实是值的副本,对副本的操作不影响到原始值
2. 如果使用了ref/out传递参数,那么传递的是存储了值类型数据的栈空间地址,则原始值和方法形参指向同一个地址空间,在方法里面进行的修改会影响到原始值。
3. ref侧重于输入,out侧重于修改。如果使用out传递参数,那么:1.在方法里面必须对传入的参数进行值的修改(赋值);2.传入参数前可以不为实参赋值
十四、面向对象的理解:一种分析解决问题的方式,当你需要完成一个功能,就去找能够实现这个功能的对象。(你要谈恋爱就得去找对象)
1. 封装:属性封装,方法 ,类,程序集都是封装
2. 继承
3. 多态
十五、this:表示当前创建的对象,this就代表当前对象
十六、类的对象的关系:
1. 类是用来描述事物的,是模型,是一个概念,它的成员:属性(描述的对象的特征) 方法(描述的对象的行为)
2. 对象是类的实例,是具体的存在。
十七、构造函数:构建类的对象时调用。一个特殊的方法:返回值,重载,传递参数
1. 没有返回值,名称和类名一致,任何成员(除了构造函数)名称都不能和类名一致
2. 每一个类都会有一个默认的无参的构造函数。
3. 构造函数不能像普通方法一样显示调用,只能创建对象的时候调用,以及子类显式地调用父类的构造函数
4. 如果人为添加了带参的构造函数,那么系统默认生成的无参构造函数会自动消失。所以一般我们应该养成一个习惯:创建好一个类,立刻为其添加无参的构造函数,避免不必要的错误
5. 构造函数可以重载。
十八、属性:对象的特征:
1. 属性的作用:封装字段,提供一种过滤的方式,过滤不合理的输入数据
2. 属性的本质:两个方法 Set()设置值 Get()获取值
3. 属性封装的实现:value相当于一个隐藏的参数,它就是用户赋的值。
4. 如果过滤:做验证:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Students { int age; public int Age { get { return age; } set { if (value > 100 || value < 0)//value > 100 || value < 0则设为默认值 { age = 18; } else { age = value; } } } }
十九、继承 this,base的理解
1. 如果子类拥有与父类重名的属性和方法,子类的属性和方法会将父类的覆盖掉。如果需要显式调用父类的成员,则需要使用<base.成员>,不然会默认调用<this.成员>,this,base都是在同一个类中才能使用
2. 创建一个子类对象,默认先会自动调用父类的无参的构造函数。如果父类没有无参的构造函数,会报错。
3. 创建子类对象的时候,也可以指定调用父类的带参的构造函数。<当前类构造函数:base.构造函数>
4. 子类会继承父类的所有成员,但是只能使用public的,而private成员不能使用。
5. 继承有三大特性:
a) 单根性:一个类只能继承自另外一个类,只能有一个父类
b) 传递性:一个类是另外一个类的子类,也可能同时是另外一个子类的父类
c) 单向性:不能循环依赖
二十:多态的实现:同一种操作,多种不同的响应
1. 声明父类变量,实例化子类对象
2. 父类创建虚方法,子类做重写。
3. 虚方法提供了默认的实现,子类可以不重写,如果子类没有重写,那么就默认调用父提供的方法实现。如果子类重写了,系统会自动判断子类类型,调用子类的重写方法 -----这就是多态
4. 多态的核心在于:子类可以替换父类,原因:
a) 子类拥有父类所规范的所有属性和方法
b) 子类还可以拥有自己特定的属性和方法
c) 父类对象可以完成的功能子类对象都可以完成(是指在其他类中实例化后,因为其他类中,只能访问public成员)
d) 所以,子类可以替换父类。如Person per=new Student();
e) Per本质是一个子类对象,但是编译器不知道,所以per只能调用父类里面的成员。如果做强制转换,则可以调用到子类成员。
5. 如果需要系统自动判断类型,达到多态的目的需要做以下事情:
a) 实现继承
b) 父类中声明虚方法(抽象方法),子类做重写(override)
c) 声明父类变量,实例化子类对象/父类做为参数,传入子类对象。
6. 多态实现了避免反复的判断才能达到的效果,这也是多态的好处。