虚拟现实项目开发C#入门
开始你的C#学习
Console.WriteLine("");//输出一段信息到控制台中显示
Console.ReadKey();//等待用户输入信息,防止屏幕一闪而过
注释方式
注释方式为单行注释和多行注释
注释是写给人看的,而不是写给计算机看的,因此注释不会被编译器运行
单行注释//,能够注释一行代码
多行注释为/*...*/,其中...为注释的多行代码
当代码被注释时,代码段会变成绿色
C#变量和常量
C#有15个预定义类型,13个是值类型,2个是引用类型(string和object)
自定义类型:值类型(struct、enum),引用类型(class)
数据类型
值类型
| c#关键字 | 说明 | 范围和精度 |
| bool | 逻辑值(真或假) | true, false |
| sbyte | 8位有符号整数类型 | 128-127 |
| byte | 8位无符号整数类型 | 0-255 |
| short | 16位有符号整数类型 | -32768-32767 |
| ushort | 16位无符号整数类型 | 0-65535 |
| int | 32位有符号整数类型 | -2147483648-2147483647 |
| uint | 32位无符号整数类型 | 0-4294967295 |
| long | 64位有符号整数类型 | -9223372036854775808-9223372036854775807 |
| ulong | 64位无符号整数类型 | 0-18446744073709551615 |
| char | 16位字符类型 | 所有的Unicode编码字符 |
| foat | 32位单度浮点类型 | (大约7个有效十进制数位) |
| double | 64位双精度浮点类型 | (大约15-16个有效十进制数位) |
| decimal | 128位高精度十进制数类型 | (大约28-29个有效十进制数位) |
预定义引用类型
引用类型包括class(类)、interface(接口)、数组、delegate(委托)、object和string。其中object和string是两个比较特殊的类型。object是c#种所有类型(包括所有值类型和引用类型)的根类。string类型是一个从object类直接继承的密封类型(不能再被继承),其示例表示Unicode字符串。
一个引用类型的变量不存储它们所代表的实际数据,而是存储实际数据的引用。引用类型分两步创建:首先在堆栈上创建一个引用变量,然后在堆上创建对象本身,再把这个内存的句柄(也是内存的首地址)赋给引用变量。
object类型
object类型就是最终的父类型,可以使用object引用绑定任何子类型的对象
字符串类型
string类型表示0或更多Unicode字符组成的序列。string是.NET Framework中String的别名
值类型和引用类型的区别图解
变量
随着程序的运行而改变其表示的值
声明变量就是在内存当中指定一个存储目标数据的区域
变量的声明
标识符必须以字母或者 (下划线) 开头,后面跟字母、数字和下划线的组合。但C#是大小写敏感的语言,name、Name分别代表不同的标识符,在定义和使用时要特别注意。另外变量名不能与C#中的关键字相同,除非标识符是以@作为前缀的。
数据类型 + 变量名 = 赋值
eg:
int a = 6;
float b = 15.3f;
选择合适的变量的数据类型
小数类型、整数类型、字符串类型、状态类型
float price = 20.12f;//定义一本书的售价为20.12元
int car_size = 5;//一辆小汽车的乘坐人数为5人
string str = "大家来学C#";//输出信息为"大家来学C#"
bool light = true;//表示灯泡的开状态
变量名的命名规范
1.为变量命名时要遵循C#语言的命名规范
2.变量名只能由字母、数字和下划线组成,而不能包含空格、标点符号、运算符等其他如@等符号3.变量名不能与C#中的关键字名称相同
变量命名规则
1.匈牙利命名规则
在变量和函数名中加入前缀以增进人们对程序的理解。例如所有男的字符变量均以ch为前缀。如命名性别的变量:
char chSeX = '男';
2.Pascal命名规则
将标识符的首字母和后面连接的每个单词的首字母都大写。如命名一个学生的年龄:
int StudentAge =20;
3.驼峰命名规则
是指混合使用大小写字母来构成变量和函数的名字。第一个单字以小写字母开始:第二个单字的首字母大写或每一个单字的首字母都采用大写字母。 如命名一个学生的姓名:
string strStudentnameA;
变量命名建议
1.变量名最好以小写字母开头
2.变量名应具有描述性质
3.在包含多个单词的变量名中,从第二个单词开始,每个单词都采取首字母大写的形式
数据类型转换
隐式转换
int a;
object b = a;
显式转换
新类型名 变量名 = (新类型名) 需要转换的变量名;
int a = 5;
object b = (object)a;
强制转换
强制转换为int,Convert.ToInt32
强制转换为float,Convert.ToSingle
强制转换为double,Convert.ToDouble
强制转换为string,Convert.ToString
装箱与拆箱
装箱的操作:把值类型转换为引用类型
1.首先从托管堆中为新生成的引用对象分配内存
2.然后将值类型的数据拷贝到刚刚分配的内存中
3.返回托管堆中新分配对象的地址。
int a;
object b = a;
拆箱的操作:把引用类型转换为值类型,必须显式转换
int c = (int)a;
可以看出,进行一次装箱要进行分配内存和拷贝数据这两项比较影响性能的操作
常量
常里用于在整个程序中将数据保持同一个值,通常可以分为字面常量和符号常量
1.对于一个整数值,默认的类型就是能保存它的最小整数类型,其类型可以分为int、uint、long或ulong。如果默认类型不是想要的类型,可以在常量后面加后缀(U或L)来明确指定其类型。在常量后面加L或l(不区分大小写)表示长整型。例如:
32// 这是一个int类型
32L// 这是一个long类型
在常量后面加U或u(不区分大小写)表示无符号整数。例如:
128U// 这是一个uint 类型
128UL// 这是一个ulong类型
整型常量既可以采用十进制也可以采用十六进制,不加特别说明默认为十进制,在数值前面加0x(或0X)则表示十六进制数,十六进制基数用0~9、A~F(或a~f),例如:
0x20//十六进制数20,相当于十进制数32
2.一般带小数点的数或用科学计数法表示的数都被认为是浮点数,它的数据类型默认为double类型,但也可以加后缀符表明三种不同的浮点格式数。
在数字后面加F(f)表示是foat类型。
在数字后面加D(d)表示是double类型。
在数字后面加M(m)表示是decimal类型
const关键字表示的是常量,常量值是无法改变的
const 数据类型 常量名 =常量值;
表达式与运算符
基本语法同c/c++点击进入
在表达式中,操作数的数据类型可以不同,只要相互兼容即可。当表达式中混合了几种不同的数据类型时,C#会基于运算的顺序将它们自动转换成同一类型。
1.一个操作数是decimal类型,另一个操作数提升为decimal,但float或double类型不能自动提升为decimal。
2.一个操作数是double类型,另一个操作数提升为double。
3.一个操作数是float类型,另一个操作数提升为float。
4.一个操作数是ulong类型,另一个操作数提升为ulanq,但带符号数,如svte、short、int或long不能自动提升。
5.一个操作数是long类型,另一个操作数提升为long。
6.一个操作数是uint类型,另一个操作数若是sbyte、short或int,那么这两个操作数都提升为long。
7.一个操作数是uint类型,另一个操作数提升为uint。
8.除以上情况之外,两个数值类型的操作数都提升为int类型。
设置值类型为空值:
自动转换类型:var
流程控制语句
选择结构语句
if-else选择结构用于根据表达式的值执行的语句,语法:
if (<条件>)<语句块>
else if<语句块>
else<语句块>
switch case选择用于根据准确的值进行选择执行语句,语法:
switch(选择变量)
{
case 值1:...:break;
case 值2:...:break;
case 值3:...:break;
default:break;
}
循环结构语句
循环结构用于对一组命令执行一定的次数或反复执行一组命令直到指定的条件为真。
while循环反复执行指定的语句,直到指定的条件为真,语法:
while(条件)
{
//语句
}
do while 循环与 while 循环类似,二者区别在于 do while循环中即使条件为假时也至少执行一次该循环体中的语句,语法:
do
{
//语句
}while(条件);
死循环由于编写代码错误或程席逻辑错误而定义了永远无法终止的循环时,便成了无限循环,又称为死循环。
for循环要求只有在对特定条件进行判断后才允许执行循环,这种循环用于将某个语句或语句块更复执行预定次数的情形。语法:
for(初始值;条件;增/减)
{
//语句
}
Console.Write表示输出为1行,Console.WriteLine();代表输出回车
输出元素用{idx}括住,idx从数字0依次递增
转向语句
break立即终止循环
continue立即终止当前循环,进行下一次循环
goto可以跳出循环,转到已经标记好的代码位置上
return跳出循环及其所包含的函数体
数组
数组的定义
数组是同一数据类型的一组值。数组属于引用类型,因此存储在堆内存中数组元素初始化或给数组元素赋值都可以在声明数组时或在程序的后面阶段中进行。
语法:数据类型[元素个数] 数组名称;(索引号是从0开始的)
int[] intScore = { 45, 62, 32, 61, 32 };//在定义时给数组赋值
string[] stuNames = new string[3];//只定义数组长度,并没有赋值
stuNames[0] = "朱奕锦";//通过索引去给数组中的元素赋值
数组访问
<数组名>.Length为数组的大小
for (int i = 0; i <= intScore.Length - 1; i++)
{Console.Write("{0} ", intScore[i]);
}
一维数组
<数据类型>[] = new <数据类型>[数组大小];
数组元素个数:<数组名>.Length;
二维数组
<数据类型>[,] = new <数据类型>[行数,列数];
数组行数:<数组名>.GetLength(0);
数组列数:<数组名>.GetLength(1);
数组元素个数:<数组名>.Length;
数组的扩容和缩容
数组扩容
在原有的定长的数组中增加长度,需要将之前的数据复制到新增的数组中,步骤如下
假设需要扩容的数组为
int[] intScore = { 45, 62, 32, 61, 32 };
int[] tmp = new int[intScore.Length + 1];
int addnum = Convert.ToInt32(Console.ReadLine());
tmp[tmp.Length - 1] = addnum;
数组缩容
首先找到需要删除的元素索引idx,而后
int[] intScore = { 45, 62, 32, 61, 32 };
int[] tmp = new int[intScore.Length - 1];
for(int i = 0;i <= intScore.Length - 1;i ++ )
{
if(i >= idx)temp[i] = intScore[i + 1];
else temp[i] = intScore[i ];
}
数组冒泡排序
将排序元素看作是竖着排列的“气泡”,较小的元素比较轻,从而“上浮”。例如:
int[] intScore = { 45, 62, 32, 61, 32 };
for(int i = 1;i < intScore.Length;i ++ )
{for(int j = 1;j < intScore.Length;j ++ ){if (intScore[j - 1] > intScore[j]){int t = intScore[j - 1];intScore[j - 1] = intScore[j];intScore[j] = t;}}
}
for (int i = 0; i < intScore.Length; i++) Console.Write("{0} ", intScore[i]);
数组列表集合
需要引入集合的命名空间
using System.Collections;
数组列表集合ArrayList 类似一维数组,数组列表是动态数组,可以存放任何对象,常用方法:
增加元素-Add
插入元素-Insert
删除元素-Remove
using System.Collections;
using System.Runtime.CompilerServices;ArrayList arrList = new ArrayList();
arrList.Add(5);
arrList.Add(2);
arrList.Add(0);
arrList.Add(1);
arrList.Add(3);
arrList.Add(1);
arrList.Add(4);
Console.WriteLine("数组的容量是:"+arrList.Capacity);
foreach (object o in arrList)
{Console.WriteLine(o);
}
Console.WriteLine("排序之后的ArrayList");
//排序arrList元素
arrList.Sort();
foreach (object o in arrList)
{Console.WriteLine(o);
}
//向ArrayList插入元素
arrList.Insert(0, 78);
Console.WriteLine("插入之后的ArrayList");
foreach (object o in arrList)
{Console.WriteLine(o);
}
//向ArrayList中删除元素
//通过值删除
arrList.Remove(78);
Console.WriteLine("删除之后的ArrayList");
foreach (object o in arrList)
{Console.WriteLine(o);
}
//通过索引删除
arrList.RemoveAt(0);
Console.WriteLine("删除之后的ArrayList");
foreach (object o in arrList)
{Console.WriteLine(o);
}
模拟随机抽取学生
using System.Collections;
using System.Runtime.CompilerServices;ArrayList arrList = new ArrayList();//定义学生数组
arrList.Add("张一");
arrList.Add("张二");
arrList.Add("张三");
arrList.Add("张四");
arrList.Add("张五");
ArrayList arrChou = new ArrayList();//定义抽取数组
for(int i = 1;i <= 2;i ++ )//进行抽取两个人
{while(true){int randIndex = new Random().Next(0,5);//随机索引if (arrChou.Contains(arrList[randIndex])) continue;//索引已抽过,继续抽else//索引未抽过{arrChou.Add(arrList[randIndex]);//存入抽取数组break;//跳出死循环}}
}
foreach(object o in arrChou)//遍历输出
{Console.WriteLine(o);
}
字符串和日期操作
比较字符串
比较字符串是指按照字典排序规则,判定两个字符串的相对大小,常用的比较字符串的方法包括: CompareCompareTa、Equals、比较运算符等。
附:按照字典规则,在英文字典中,出现在前面的单词小于出现在后面的单词。
Equals方法用于方便地判断两个字符串是否相同。
如果相同,返回值为True;否则为False。
定位字符和字串
定位子串是指一个字符串中寻找其中包含的子串或者某个字符。 常用的定位子串和字符的方法包括IndexOf、LastIndexof、StartWith、Endwith等。
补充说明:
Indexof/LastIndexOf方法用于搜索一个字符串中,某个特定的字符或子串第一次/最后一次出现的位置,该方法区分大小写,并从字符串的首字符开始以0计数。如果字符串中不包含这个字符或子串,则返回-1。
格式化字符串
Format方法用于创建格式化的字符串以及连接多个字符串对象。形式如下:
Format(string format,params object[] args)该方法的参数format用于指定返回字符串的格式,经常在format参数中包含一些大括号扩起来的数字,如{0}、{1},这些数字分别一一对应于args参数数组中的变量。
| 格式字符 | 说明和关联属性 |
| c、C | 货币格式 |
| d、D | 十进制格式 |
| e、E | 科学计数(指数)格式 |
| f、F | 固定点格式 |
| g、G | 常规格式 |
| h、H | 数字格式 |
| n、N | 用分号隔开的数字 |
| x、X | 十六进制格式 |
链接字符串
1.Concat方法用于连接两个或多个字符串。
2.Join方法利用一个字符数组和一个分割字符串构造成新的字符串,常用于把多个字符串连接在一起,并用一个特殊的符号来分隔开。
3.连接运算符“+”,可以方便地连接多个字符串。
分裂字符串
Split方法可以把一个字符串,按照某个分隔符,分裂成一系列小的字符串。
字符串的其他操作列举
1.替换字符串
如果想要替换字符串中某些特定的字符或者某个子串,可以使用Replace方法来实现。
2.字符串转化为大写和小写
String类提供了方便转换字符串中所有字符大小写的方法ToUpper和ToLower。
日期操作
获取当前日期:
DateTime dtime = DateTime.Now;
string strtime = dtime.ToString("yyyy年MM月dd日 HH时mm分ss秒");
字符串和日期操作相关代码块
using System;
class Programe
{static void Main(){string strA = "zhuyijin";string strB = "duyiang";//字符串的比较int flag = strA.CompareTo(strB);Console.WriteLine(flag);//字符串的定位int index = strA.IndexOf('j');Console.WriteLine(index);//字符串的格式化string strC = string.Format("{0}{1}{2}一生一世!", 5, 2, 0);Console.WriteLine(strC);double dMoney = 1433223.5201314;Console.WriteLine(dMoney);string strMoney = string.Format("{0:c}", dMoney);Console.WriteLine(strMoney);//字符串的链接string strt = string.Concat(strA, strB);Console.WriteLine("通过Concat方法链接的字符串为:"+strt);string strt2 = string.Join(strA, strB, new char[] { '+' });Console.WriteLine("通过Join方法链接的字符串为:"+strt2);string str3 = strA + strB;Console.WriteLine(str3);//分裂字符串string strtext = "张三,-李四=,王五";string[] strArrays = strtext.Split(new char[] {',' ,'-','='});foreach (string o in strArrays){//判断字符串是否为空格if (!string.IsNullOrEmpty(o)){Console.WriteLine(o);}}//清空字符串里的空格(包括字符串前导和后导部分)string str1 = " aaa ";Console.WriteLine("字符串清空之前的长度:" + str1.Length);str1 = str1.TrimStart();str1 = str1.TrimEnd();Console.WriteLine("字符串清空之后的长度:" + str1.Length);//字符串的替换string strH = "Hello";Console.WriteLine("字符串替换之前:" + strH);strH = strH.Replace('o', 'g');Console.WriteLine("字符串替换之后:" + strH);//字符串的大小写转换string stro = "abcdefg";stro = stro.ToUpper();Console.WriteLine("字符串转换为大写:" + stro);stro = stro.ToLower();Console.WriteLine("字符串转换为小写:" + stro);//获取现在日期DateTime dtime = DateTime.Now;string strtime = dtime.ToString("yyyy年MM月dd日 HH时mm分ss秒");Console.WriteLine("输出日期为:"+strtime);}
}
面向对象编程基础
类的概念
1.什么是类?
类是一组具有相同数据结构和相同操作的对象的集合。类是对一系列具有相同性质的对象的抽象,是对对象共同特征的描述。
2.对象和类之间的关系?
对象可以是现实生活中的一个物理对象,还可以是某一类概念实体的实例。例如:一辆汽车、一个人,一本书,乃至一种语言、一个图形、一种管理方式,都可以作为一个对象。
类是一组具有相同数据结构和相同操作的对象的集合。类是对一系列具有相同性质的对象的抽象,是对对象共同特征的描述。比如每一辆汽车是一个对象的话,所有的汽车可以作为一个模板,我们就定义汽车这个类。
可以使用类的定义实例化对象,这表示创建该类的一个实例,从类定义中产生对象,必须有建立实例的操作。
类的定义
1.类的定义包括类头和类体两部分,其中类体用一对大花括号{}括起来,类体用于定义该类的成员,语法形式:
{
[类成员声明]
}
类成员由两部分组成,一个是类体中以类成员声明形式引入的类成员,另一个则是直接从它的基类继承而来的成员。类成员声明主要包括: 常数声明、字段声明、方法声明、属性声明、事件声明、索引器声明、运算符声明、构造函数声明、析构函数声明、静态构造函数、类型声明等。
2.字段声明
语法形式:
[属性集信息] [字段修饰符] 类型 变声明列表;
其中:
变量声明列表一一标识符或用逗号“,”分隔的多个标识符,并且变量标识符还可用赋值号“=”设定初始值。
构造函数
构造函数是类的一种特殊方法,每次创建类的实例都会调用它
[访问修饰符] 类名()
{
//造函数的主体
}
参数化构造函数
[访问修饰符] 类名(参数列表)
{
//造函数的主体
}
this关键字
this仅限于在构造函数、类的方法和类的实例中使用。
在类的构造函数中出现的this作为一个值类型,它表示对正在构造的对象本身的引用;在类的方法中出现的this作为一个值类型,它表示对调用该方法的对象的引用;在结构的构造函数中出现的this作为一个变量类型,它表示对正在构造的结构的引用;在结构的方法中出现的this作为一个变量类型,它表示对调用该方法的结构的引用;经常在构造函数或者类方法中,如果传入参数和类字段同名,一定需在类字段前加上this。
方法
意义:表示对象的行为
语法:
[访问修饰符][返回类型]<方法名>([参数列表])
{
// 方法主体
}
访问修饰符 (可选),默认情况下为 private
如果不需要返回任何值,方法可能返回 void数据类型
方法的调用
语法:
对象名.方法名([参数列表]);
实例点号类中的方法
方法的参数
C#中方法的参数有四种类型:
值参数,不含任何修饰符。
引用型参数,以ref 修饰符声明。
输出参数,以out 修饰符声明。
数组型参数,以params 修饰符声明。
静态类和静态方法
类的数据成员可以分:静态字段和实例字段。
静态字段是和类相关联的,不依赖特定对象的存在实例字段是和对象相关联的,访问实例字段依赖于实例的存在
含义与用法:
通常若一个方法声明中含有static修饰符,则表明这个方法是静态方法,同时说明它只对这个类中的静态成员操作,不可以直接访问实例字段。
若一个方法声明中不包含static修饰符,则该方法是一个实例方法。一个实例方法的执行与特定对象关联,所以需要一个对象存在。实例方法可以直接访问静态字段和实例字段。
方法的重载
重载方法有两种方式
1.指定不同个数的参数
2.指定不同类型的参数
命名空间的集合
namespace命名空间的名称
{
//该名称空间的所有类都存放在这里
}
相关代码及类的定义
using Console1;
using System;
using System.Net.Http.Headers;class Programe
{static void Main(){//对象、根据类来定义的Student stu = new Student();//new就是在内存中分配存储数据区域stu.name = "张三";stu.stuno = 1001;stu.age = 21;Console.WriteLine("学生的姓名:" + stu.name);Console.WriteLine("学生的学号:" + stu.stuno);Console.WriteLine("学生的年龄:" + stu.age);//根据有参构造函数来实例化对象Student stu1 = new Student("张三",1001,21);Console.WriteLine("学生的姓名:" + stu1.name);Console.WriteLine("学生的学号:" + stu1.stuno);Console.WriteLine("学生的年龄:" + stu1.age);Person p = new Person("");Console.WriteLine(p.Say());//实例化的对象//方法在调用的时候所传递的参数为实参Console.WriteLine(p.DoWork("程序员"));p.Do();OperaterMethod opm = new OperaterMethod(10, 20);int addresult = opm.Add();int divresult = opm.Div();Console.WriteLine("这是两个数相加的和" + addresult);Console.WriteLine("这是两个数相减的差" + divresult);//值参数int myage1 = 18;Person p1 = new Person("");//值参数传递,克隆了一个值p.ChangeAge1(myage1);Console.WriteLine("值参数->"+myage1);//引用参数int myage2 = 18;Person p2 = new Person("");//值参数传递,克隆了一个值p.ChangeAge2(ref myage2);//原有的数据必须先赋值Console.WriteLine("引用参数->" + myage2);//输出参数//ref和out之间的区别,虽然都是引用的原有的数据进行操作//使用ref的数据在使用前必须赋值//使用out类型的参数可以赋值也可以不用赋值double dweight;p.ChangeWeight(out dweight);//原有的数据可以不赋值Console.WriteLine("体重:" + dweight);//数组形参数int[] myages = { 12, 13, 14 };p.ShowInfo(myages);//静态类和静态方法Person.Country = "中国";Console.WriteLine(Person.Country);Person.ChangeCountry();Console.WriteLine(Person.Country);Person p3 = new Person("李四");p3.ShowInfo();//方法的重载PhoneCost p4 = new PhoneCost();p4.ChongHuaFei(12);p4.ChongHuaFei("朱奕锦");p4.ChongHuaFei("朱奕锦",12);}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{public class PhoneCost{//方法重载必须要求的是方法的名字和返回类型必须一致//方法的参数个数不一致//方法的参数类型不一致public void ChongHuaFei(string str,double d){Console.WriteLine("给:" + str + "冲了" + d);}public void ChongHuaFei(string str){Console.WriteLine(str + "充话费");}public void ChongHuaFei(double d){Console.WriteLine("充了:" + d);}}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{public static class OperatorMethod{//public int dresult;在静态类当中不允许出现实例化的字符按或者方法public static int result;public static int Add(int a,int b){result = a + b;return result;}}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{public class Person{public string Say(){string str = "这是说话的方式";return str;}public string DoWork(string jobname){string str = "我做的工作是:" + jobname;return str;}public void Do(){Console.WriteLine("这是Person里的Do方法");}public void ChangeAge1(int age){age = age + 10;}public void ChangeAge2(ref int age){age = age + 10;}public void ChangeWeight(out double d){d = 120;}public void ShowInfo(params int[] showages)//用于变长数组{foreach(int i in showages){Console.WriteLine(i);}}//static表名是一个静态的字段,所谓的静态字段是长期驻留在内存中的public static string Country;//如果一个方法是静态方法的话,那么必须加上static修饰public static void ChangeCountry(){Person.Country = "美国";}public string name;//实例化的字段public Person(string _name){this.name = _name;}//实例化的方法public void ShowInfo(){Console.WriteLine("我的姓名:" + name + " 我来自:" + Country);}//静态方法可以访问静态字段public void ShowCountryInfo(){this.name = "李四";Console.WriteLine("国家的名称是:" + Country);}}
}
面对对象的属性
封装
字段
字段表示类或结构中的对象或值
字段使类和结构可以封装数据
例如:
public class Employee
{private string _name;//字段private uint _age;//字段...
}
属性
属性是对现实世界中实体特征的抽象,它提供了对类或对象性质的访问。C#中的属性更充分地体现了对象的封装性: 不直接操作类的数据内容,而是通过访问器进行访问,它借助于get和set对属性的值进行读写。
相关代码
using Console1;
using System;
using System.Net.Http.Headers;class Programe
{static void Main(){BankCount bcount = new BankCount("1001",100,"张三");Console.WriteLine("取款金额:");double d = Convert.ToDouble(Console.ReadLine());bcount.Bankmoney = bcount.Bankmoney - d;Console.WriteLine("剩余金额:" + bcount.Bankmoney);}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{public class BankCount{//保证数据的安全性,对字段进行封装,所谓的封装,就是不能把字段暴露在外面直接访问或设置。//提供一种机制能够在字段进行赋值的时候进行检查--属性。通过属性对这个字段进行访问或设置。//设置private权限就不能在外部对这个类的字段进行直接的操作private string cardid;private double bankmoney;private string name;//一般外面在外部可以直接对属性进行操作,所以它的属性就是publicpublic string Cardid{//get//表示我们在访问属性的时候,所对应访问的字段//{// return cardid;//}set//隐式参数value,表示即将赋值的数据{cardid = value;}}public double Bankmoney{get//表示我们在访问属性的时候,所对应访问的字段{return bankmoney;}set//隐式参数value,表示即将赋值的数据{if(value < 0){bankmoney = 0;}else{bankmoney = value;}}}public string Name{get//表示我们在访问属性的时候,所对应访问的字段{return name;}set//隐式参数value,表示即将赋值的数据{name = value;}}public BankCount() { }public BankCount(string _cardid,double _bankmoney,string _name){cardid = _cardid;bankmoney = _bankmoney;name = _name;}}
}
继承
继承是面向对象语言的基本特征,是实现代码复用的手段。继承使得在原有的类基础之上,对原有的程序进行扩展,从而提高程序开发的速度,实现代码的复用。
相关代码
using Console1;
using System;
using System.Net.Http.Headers;class Programe
{static void Main(){Doctor d = new Doctor("张三","男",12,"口腔科");Student s = new Student("李四","女",21,"扶沟高中");//Console.WriteLine("医生的姓名:" + d.Name);//Console.WriteLine("医生的性别:" + d.Sex);//Console.WriteLine("医生的年龄:" + d.Age);//Console.WriteLine("医生的科室:" + d.Department);d.ShowInfo();s.ShowInfo();}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{public class Student:Person{private string schoolname;private string Schoolname{get {return schoolname;}set{schoolname = value;}}public Student(string _name,string _sex,int _age,string _schoolname):base(_name,_sex,_age){this.schoolname = _schoolname;}//override是针对父类中已经定义好的虚方法virtual可以进行重写public override void ShowInfo(){Console.WriteLine("姓名:" + this.Name + ",学校名称:" + this.Schoolname);}}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{//作为继承的,称之为基类(父类)public class Person{//字段定义private string name;private string sex;private int age;//字段进行封装public string Name {get{return name;}set{name = value;}}public string Sex {get{return sex;}set{sex = value;}}public int Age{ get{return age;}set{if (age <= 0){age = 12;}else age = value;}}//有参的构造函数public Person(string _name,string _sex,int _age){name = _name;sex = _sex;age = _age;}//无参的构造函数public Person() { }public virtual void ShowInfo(){Console.WriteLine("姓名:" + this.Name + ",性别:" + this.Sex + ",年龄," + this.Age);}}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;namespace Console1
{//称之为派生类,也称之为子类//从Person中继承了非private的属性public class Doctor:Person{private string department;public string Department{get{return department;}set{department = value;}}//base表示父类的public Doctor(string _name,string _sex,int _age,string _department) : base(_name, _sex, _age) {department = _department;}//new表示对于父类方法的覆盖public new void ShowInfo(){Console.WriteLine("姓名:" + this.Name + ",性别:" + this.Sex + ",年龄," + this.Age + ",所在科室:" + this.Department);}}
}
多态
抽象类
abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。
在类声明中使用abstract 修饰符以指示某个类只能是其他类的基类。
标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。
抽象类的特征
1.抽象类不能实例化。
2.抽象类可以包含抽象方法和抽象访问器
3.不能用 sealed(密封类)修饰符修改抽象类
4.从抽象类派生的非抽象类必须包括继承方法和抽象访问器的实现
接口
接口(interface)定义了一个可由类和结构实现的协定。接口可以包含方法、属性、事件和索引器。
接口不提供它所定义的成员的实现 - 它仅指定实现该接口的类或结构必须提供的成员。
案例应用
为了实现跨行转账业务,定义了一个接口,该接口包含一个用于存取款的方法和一个返回余额的属性。
接口总结
1.一个接口声明可以声明零个或多个成员。
2.接口的成员必须是方法、属性、事件或索引器。
3.接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型,也不能包含任何种类的静态成员。
4.所有接口成员都隐式地具有 public 访问属性。
5.接口成员声明中包含任何修饰符都属于编译时错误。具体来说,禁止使用修饰符 abstract、public、protected、internal、privatevirtual、override 或 static 来声明接口成员。
多重接口实现
C 不允许多重类继承
但 C* 允许多重接口实现
这意味着一个类可以实现多个接口
相关代码
using Console1;
using System;
using System.Net.Http.Headers;class Programe
{static void Main(){//多态:不同对象对同一方法做出不同的实现,这种方式就称之为面向对象中的多态行为//抽象类不能够被直接实例化,只能够通过其子类进行实例化//Animal animal = new Animal();Animal dog = new Dog();//父类对象指向子类的引用。父类为抽象类,具体实现的是由子类来实现dog.Animalcolour = "红色";dog.Weight = 12.3;dog.Show();dog.ShowIt();dog = new Pig();dog.ShowIt();UserCad u = new UserCad();u.BankMoney = 200;u.Zhuan(100);Console.WriteLine("卡上的余额是:" + u.BankMoney);u.Zhuan(120);Console.WriteLine("卡上的余额是:" + u.BankMoney);}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{//银行卡的类//实现接口的时候,如果是显示实现,那么在实现的方法或属性前就会加上所属的接口的名称//隐式实现接口的时候,那么在实现的方法或属性前不需要加所属接口的名称//并且会加上public访问权限internal class UserCad : IBank{//显示实现//double IBank.BankMoney { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }//void IBank.Zhuan(double dZhuan)//{// throw new NotImplementedException();//}//隐式实现private double bankmoney;public double BankMoney { get{return this.bankmoney;}set{if(value < 0){this.bankmoney = 0;}else{this.bankmoney = value;}}}public void Zhuan(double dZhuan){this.bankmoney = this.bankmoney - dZhuan;}}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{//表示这是一个接口//接口只是对于方法的定义//抽象类和接口的典型的区别,就是抽象类有字段和属性,接口是没有字段和属性的//抽象类只能单一继承,也就是一个类只能继承一个抽象类//而接口可以多重继承的,也就是一个类可以继承一个或者多个接口interface IBank{double BankMoney { get; set; }//定义了一个接口,在这个接口中只有方法的定义,没有方法的实现//它是一个特殊的抽象方法,一个是方法的修饰没有abstract关键字//子类在实现接口的时候,不必像抽象方法一样需要用override关键字public void Zhuan(double dZhuan);}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{public class Pig:Animal{public override void ShowIt(){Console.WriteLine("这是猪的ShowIt方法实现");}}
}
C#集合的处理
哈希表集合
Hashtable集合是键/值对的集合,DictionaryEntry类型的实例,DictionaryEntry类型有一个Key和Value属性来读取和设置健和值。
动态存放键/值对

相关代码
using Console1;
using System;
using System.Net.Http.Headers;
using System.Collections;//引用哈希表的命名空间class Programe
{static void Main(){//使用哈希表Hashtable hash = new Hashtable();//哈希表中数据的添加(key,value)hash.Add(1,"hello");hash.Add(2, "world");hash.Add(3, "C#");//访问hash里的数据//采用键的方式进行访问Console.WriteLine(hash[1]);Console.WriteLine(hash[2]);Console.WriteLine(hash[3]);//采用遍历它的键集合var skeys = hash.Keys;foreach (var key in skeys) Console.WriteLine("键:{0},值:{1}", key, hash[key]);//采用遍历器var ie = hash.GetEnumerator();//获取遍历器while(ie.MoveNext())//依次遍历集合中的数据,类似于游标{Console.WriteLine("键:{0},值:{1}", ie.Key, ie.Value);}}
}
泛型的应用
泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性。
在泛型类型或泛型方法的定义中,类型参数是一个占位符(placeholder),通常为一个大写字母。
字典集合
键值对的存储,这样的存储可以使用泛型
相关代码
using System;
using System.Net.Http.Headers;
using System.Collections;//使用ArrayList
using System.Collections.Generic;//使用泛型
using System.Transactions;class Programe
{static void Main(){ArrayList arrList = new ArrayList();arrList.Add(1);arrList.Add("Hello");arrList.Add(DateTime.Now);//数据类型不安全//在使用arrList时,无法保证类型的一致性//泛型的特点就是类型的安全List list = new List();list.Add(1);list.Add(2);list.Add(3);//list.Add("hello");被识别为非法类型//泛型的遍历foreach(int i in list){Console.WriteLine("输出的数据:" + i);}Console.WriteLine("采用另外一种方式输出泛型的集合数据:");for(int i = 0;i < list.Count;i ++ ){Console.WriteLine("泛型的索引{0},所对应的数据{1}", i, list[i]);}//字典集合的存储Dictionary dic = new Dictionary();dic.Add("1001", "张三");dic.Add("1002", "李四");dic.Add("1003", "王五");//采用类似于访问哈希的方式访问字典集合的数据//采用键的方式进行访问Console.WriteLine("输出学号为1001的学生姓名:" + dic["1001"]);//采用遍历它的键集合var skeys = dic.Keys;foreach(string s in skeys){Console.WriteLine("输出学号为{0}学生姓名{1}",s,dic[s]);}//采用遍历器去访问var ie = dic.GetEnumerator();while(ie.MoveNext()){Console.WriteLine("键:{0},值:{1}", ie.Current.Key,ie.Current.Value);}}
}
异常处理
C#语言的异常处理功能可帮助您处理程序运行时出现的任何意外或异常情况。
异常处理使用 try、catch 和 finally 关键字尝试某些操作,以处理失败情况,尽管这些操作有可能失败,但如果您确定需要这样做,且希望在事后清理资源,就可以尝试这样做。
公共语言运行时(CLR)、NETFramework 或任何第三方库或者应用程序代码都可以生成异常。 异常是使用 throw 关键字创建的。
例如:
using System;
using System.Net.Http.Headers;
using System.Transactions;class Programe
{static void Main(){Console.WriteLine("请输入一个数字:");int intGetNum = Convert.ToInt32(Console.ReadLine());}
}
编译情况:

运行情况:
异常出现的时间是在程序运行的时候,程序运行的时候发生错误就需要进行异常处理

使用异常
在 C# 中,程序中的运行时错误通过使用一种称为“异常”的机制在程序中传播。 异常由遇到错误的代码引发,由能够更正错误的代码捕捉。 异常可由NET Framework 公共语言运行时(CLR)或由程序中的代码引发。一旦引发了一个异常,这个异常就会在调用堆栈中往上传播,直到找到针对它的 catch 语句。 未捕获的异常由系统提供的通用异常处理程序处理,该处理程序会显示一个对话框。
异常由从 Exception 派生的类表示。 此类标识异常的类型,并包含详细描述异常的属性。 引发异常涉及到创建一个异常派生类的实例,配置异常的属性(可选),然后使用 throw 关键字引发该对象。
相关代码
using Console1;
using System;
using System.Net.Http.Headers;
using System.Transactions;class Programe
{//异常出现的时间是在程序运行的时候,程序运行的时候发生错误就需要进行异常处理//所有的异常都是从Exception中继承的static void Main(){//Console.WriteLine("请输入一个数字:");//try//检测有可能出现的异常代码,有try必须就有catch//{// int intGetNum = Convert.ToInt32(Console.ReadLine());//}//catch (Exception ex)//{// Console.WriteLine("程序出现异常:" + ex.Message);//}//finally//表示可以写也可以不写,无论是否出现异常,finally了的程序代码都会执行//{// Console.WriteLine("这是finally里的程序代码执行");//}WriteMsg();}static void WriteMsg(){Console.WriteLine("请输入一个数字:");try//检测有可能出现的异常代码,有try必须就有catch{int intGetNum = Convert.ToInt32(Console.ReadLine());}catch (Exception ex){MyException myexception = new MyException("20", ex);myexception.ShowExcpetionMsg();}}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{//自定义的异常,异常的出现时间public class MyException:Exception{private DateTime dt;private DateTime Dt{get{return dt;}set{dt = value;}}private string codenum;private string Codenum{get{return codenum;}set{codenum = value;}}public MyException(string _codenum,Exception ex):base(ex.Message){this.codenum = _codenum;this.Dt = DateTime.Now;}public void ShowExcpetionMsg(){Console.WriteLine("异常出现的时间:" + this.Dt + ",出现异常的代码:" + this.Codenum + ",异常的信息:" + this.Message);}}
}
数据流计数
在应用程序中,经常需要用文件来保存数据,这就要用到文件的输入/输出操作。
C#对文件操作的类的结构

文件的操作
相关代码
using Console1;
using System;
using System.Net.Http.Headers;
using System.Transactions;
using System.IO;//这是一个处理文件流的命名空间class Programe
{static void Main(){创建一个文件。File类,File是静态类//string strFilePath = "D:\\text.txt";//File.Create(strFilePath);//Console.WriteLine("文件创建成功!!!");删除文件(文件没有权限、路径错误都会出现删除异常)//File.Delete(strFilePath);//Console.WriteLine("文件删除成功!!");创建一个文件夹,对于文件夹的静态操作类Directory//string strDir = "D:\\我的基本信息";//Directory.CreateDirectory(strDir);//Console.WriteLine("文件夹创建成功!!!");删除文件夹//Directory.Delete(strDir);//Console.WriteLine("文件夹删除成功");//向文件中写入数据string strFilePath = "D:\\text.txt";if(!File.Exists(strFilePath)){File.Create(strFilePath);}StreamWriter swriter = new StreamWriter(strFilePath);swriter.Write("hello,这是通过文件流写入的数据");swriter.Close();swriter.Dispose();Console.WriteLine("写入数据完毕!!");StreamReader sreader = new StreamReader(strFilePath);string strRead = sreader.ReadToEnd();Console.WriteLine("从文中读取的数据:" + strRead);sreader.Close();sreader.Dispose();}
}
文件流的操作
相关代码
using System;
using System.Net.Http.Headers;
using System.Transactions;
using System.IO;//这是一个处理文件流的命名空间class Programe
{static void Main(){//文件流(字节或字符序列的集合)//FileStream fstream = new FileStream("D:\\Example.cs",FileMode.OpenOrCreate);//StreamReader reader = new StreamReader(fstream);//string strResult = reader.ReadToEnd();//Console.WriteLine("读出的数据:" + strResult);用完之后关闭流//reader.Close();//fstream.Close();需要对于流的资源进行释放//reader.Dispose();//fstream.Dispose();采用第二种方式去读取文件的数据,转成字节码后然后再经过编码处理,通过编码处理之后得到数据//FileStream fstream = new FileStream("D:\\Example.cs",FileMode.OpenOrCreate);构建字节码//Byte[] bytes = new byte[fstream.Length];把流的数据读取到字节码//fstream.Read(bytes, 0, (int)fstream.Length);此时需要转码操作//string strGetData = System.Text.Encoding.UTF8.GetString(bytes);//Console.WriteLine("经过字节转码的数据:" + strGetData);//fstream.Close();//fstream.Dispose();//通过字节转码将数据写入到文件中FileStream fstream = new FileStream("D:\\Example.cs", FileMode.OpenOrCreate);Console.WriteLine("请输入你想输入的数据:");string strGet = Console.ReadLine();//需要把字符串数据进行转码,转成字节数组Byte[] getBytes = System.Text.Encoding.UTF8.GetBytes(strGet);//需要把字节数组写入到文件流中fstream.Write(getBytes,0,getBytes.Length);fstream.Flush();fstream.Close();fstream.Dispose();}
}
事件和委托
委托的定义
委托和类一样,是一种用户自定义的类型。但类表示的是数据和方法的集合,而委托则持有一个或多个方法,以及一系列预定义操作。
声明委托类型
委托是类型,就好像类是类型一样。与类一样,委托类型必须在被用来创建变量以及类型的对象之前声明。
相关代码
using System;
using System.Net.Http.Headers;
using System.Transactions;
using System.IO;//这是一个处理文件流的命名空间class Programe
{//关于加减乘除,它的返回类型都是double类型,并且参数都有两个参数,都是为double类型//delegate都是声明委托的关键字//语法:delegate 方法的返回类型 委托名字(方法的参数)delegate double DelOperator(double num1, double num2);static void Main(){//使用委托的时候,就需要实例化一个委托对象//在实例化委托的时候,会把方法名作为一个参数传进来,有点类似于类的有参构造函数里的参数DelOperator delOp = new DelOperator(Add);//在调用委托的时候,实际上调用的是委托所指向的这个方法delOp += new DelOperator(Div);//委托指向新方法double result = delOp.Invoke(3, 5);Console.WriteLine("委托调用的方法的执行结果:" + result);//采用另外一种方法去调用delOp -= new DelOperator(Div);//移出委托指向的方法double resulto = delOp(3, 5);Console.WriteLine("委托调用的方法的执行结果:" + resulto);}static double Add(double a,double b){return a + b;}static double Div(double a, double b){return a - b;}
}
事件

相关代码
using Console1;
using System;
using System.Net.Http.Headers;
using System.Transactions;class Programe
{static void Main(){MobileServer moserver = new MobileServer();MoblieClient moclient = new MoblieClient();moclient.DingYue();//手机客户端订阅推送消息moserver.SendMsg("今天天气晴朗");}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{public class MoblieClient{//客户端订阅服务器端推送消息的功能public void DingYue(){Console.WriteLine("手机客户端已经订阅了服务器端的推送消息!");MobileServer.sendEvent += new DelSendMsg(MobileSever_sendEvent);}void MobileSever_sendEvent(string msg){Console.WriteLine("这是客户端推送到服务器端的推送消息:" + msg);}}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Console1
{//手机服务器端的类public delegate void DelSendMsg(string msg);public class MobileServer{//事件是委托的一个实例对象public static event DelSendMsg sendEvent;//有一个方法,就是将服务器端的消息推送给客户端的方法public void SendMsg(string msg){Console.WriteLine("服务器开始给客户端的手机发送推送消息!");//如果是客户端已经订阅了该事件if(sendEvent != null){//事件的执行,事件的执行是关联到具体的事件绑定的方法执行sendEvent(msg);}}}
}
多线程开发
为什么要使用多线程
1.可以使用线程将代码同其他代码隔离,提高应用程序的可靠性。
2.可以使用线程来简化编码。
3.可以使用线程来实现并发执行。
线程相关的知识点
1、进程与线程:进程作为操作系统执行程序的基本单位,拥有应用程序的资源,进程包含线程,进程的资源被线程共享,线程不拥有资源。
2、前台线程和后台线程:通过Thread类新建线程默认为前台线程。当所有前台线程关闭时所有的后台线程也会被直接终止,不会抛出异常。
3、挂起(Suspend)和唤醒(Resume):由于线程的执行顺序和程序的执行情况不可预知所以使用挂起和唤醒容易发生死锁的情况,在实际应用中应该尽量少用。
4、阻塞线程: Join,阻塞调用线程,直到该线程终止。
5、终止线程: Abort: 抛出 ThreadAbortException 异常让线程终止,终止后的线程不可唤醒。Interrupt: 抛出 ThreadInterruptException 异常让线程终止,通过捕获异常可以继续执行。
6、线程优先级: AboveNormal BelowNormal Highest Lowest Normal,默认为Normal。
使用线程开发
1.Thread类的便用
使用Thread类可以创建和控制线程。在创建Thread对象后,就可以用Start 方法启动线程
2.给线程传递数据
相关代码
using Console1;
using System;
using System.Net.Http.Headers;
using System.Transactions;
using System.Threading;//引入线程时所需要引入的命名空间class Programe
{static void Main(){//ThreadStart定义的是不带参数的委托Thread t1 = new Thread(new ThreadStart(Test1));t1.Name = "线程1";t1.Start();//开始线程的执行t1.IsBackground = true;//后台执行//ParameterizedThreadStart定义的是带参数的委托Thread t2 = new Thread(new ParameterizedThreadStart(Text2));t2.Name = "线程2";//调整t2优先级为最高t2.Priority = ThreadPriority.Highest;t2.Start("hello");}static void Test1(){//线程的阻塞Console.WriteLine("线程阻塞两秒钟");Thread.CurrentThread.Join(2000);//Console.WriteLine("线程停止两秒执行");//Thread.Sleep(2000);//线程休眠Console.WriteLine("当前线程的执行名字:" + Thread.CurrentThread.Name);Console.WriteLine("这是线程1所执行的方法");}static void Text2(object s){Console.WriteLine("当前线程的执行名字:" + Thread.CurrentThread.Name);Console.WriteLine("这是线程2所执行的方法,方法的参数:" + s);}
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
