在20210419的基础上进行改进,和学习。
20210422笔记
①C#小知识点总结
一、C#中的数组定义
0)数组声明
①C#声明数组时,方括号[]必须跟在类型后面,而不是标识符后面。
②C#声明数组时支持分配内存的方括号内是整型变量或变量表达式,只要事先确定了变量的值即可
int[] mySigArray = new int[n];
n的值必须事先确定,声明之后即使改变n的值数组大小也不会变
例子:
// int[] ii;
//声明数组,此处仅仅声明
//创建数组,数组赋值方式有两种
//方法一
//ii = new int[4];
//ii[1] = 1;
//ii[2] = 2;
//ii[4] = 4;//其实是越界了,所以是错的
//方法二
int[]ii={1,2,3,4};//创建同时,进行赋值操作
1)一维数组:
不定长:
int[] ii= new int[]{1,2,3,4,5,6};
定长:
int[] ii= new int[3]{1,2,3};
区别在于是否在[]中填入数字
2)二维数组
不定长:
int[,] ii= new int[,]{{1,2,3},{1,2,3}};
定长:
int[,] ii= new int[2,2]{{1,2},{1,2}};
多维以此类推
区分:
声明锯齿数组(数组的数组)
int[][] mySawArray = new int[3][]; //注意与二维数组不同,这里有两个方括号
3)数组初始化
int[] a = {1,2,3,4}; //一维数组初始化
int[,] aa= {{1,2,3},{4,5,6},{7,8,9}}; //二维数组初始化
int[][] aaa= {new int[] {1,2},new int[] {3,4,5,6,7,8},new int[] {9,10,11}}; //锯齿数组初始化
4)数组的访问
① 访问上述初始化数组的单个的元素
int i = a[2]; //i=3
int j = aa[2,1]; //j=8
int k = aaa[2][1]; //k=10 注意二维数组与锯齿数组的区别
②遍历访问数组元素
1)C#提供了foreach语句,该语句提供了一种简单、明了的方法来循环访问数组
foreach(int m in myArray) //将所有数组元素的值加1,myArray可以是一维、多维或锯齿数组
{
m++;
}
C# 中 foreach 遍历的用法
1)foreach循环用于列举出集合中所有的元素,foreach语句中的表达式由关键字in隔开的两个项组成。in右边的项是集合名,in左边的项是变量名,用来存放该集合中的每个元素。
https://blog.csdn.net/beauty_1991/article/details/45197931
2)用for循环遍历数组,使用这种方式可以更好的控制数组元素(知道每次循环中的数组对象是哪个),下面这段代码用foreach语句是无法实现的
//for遍历规则数组
nt[,,] a = new int[2, 2, 2] { {{ 1, 2 }, { 3,4}},{{ 5, 6 }, { 7,8}} };//定义一个2行2列2纵深的3维数组a
for (int i = 0; i < a.GetLength (0) ;i++ ) //用Array.GetLength(n)得到数组[0,1,,,n]上的维数的元素数,0代表行,1列,n代表此数组是n+1维
{
for (int j = 0; j < a.GetLength(1); j++)
{
for (int z = 0; z < a.GetLength(2);z++ )//2代表得到纵深上的元素数,如果数组有n维就得写n个for循环
{
Console.WriteLine(a[i,j,z]);
}
}
}
for (int i = 0; i< mySawArray.Length; i++)
{
for (int j = 0; j < mySawArray[i].Length; j++)
{
myMulArray[i,j]=mySawArray[i][j]; //把锯齿数组的每个元素赋值给二维数组中相应的元素
}
}
用foreach循环一次性遍历a数组
int[,,] a = new int[2, 2, 2] { {{ 1, 2 }, { 3,4}},{{ 5, 6 }, { 7,8}} };//定义一个2行2列2纵深的3维数组a
foreach(int i in a)
{
Console .WriteLine (i);
}
3)借助foreach,只能一一取得数组中的元素,并不能利用这种语句改变数组所存储的元素。
4)foreach优点
①C#中使用数组的时候就难免疑问到底使用0开始还是用1开始呢,那么使用foreach就可以避免这类问题。
②对于多维数组操作用foreach就非常简便了
int[,] nVisited = new int[8,8];
// Use "for" to loop two-dimension array
for( int i = 0; i < nVisited.GetLength(0); i++ )
for( int j = 0; j < nVisited.GetLength( 1 ); j++ )
Debug.WriteLine( nVisited[i,j].ToString() );
// Use "foreach" to loop two-dimension array
foreach( int i in nVisited )
Debug.WriteLine( i.ToString() );
对于三维或更多维,foreach语句不用发生任何变化
③foreach完成类型转换操作,这种体现可能通过如上的例子看不出任何效果,但是对于ArrayList之类的数据集来说,这种操作就显得比较突出
// Init an arraylist object
int[] nArray = new int[100];
ArrayList arrInt = new ArrayList();
arrInt.AddRange( nArray );
// Use "foreach" to loop an arraylist
foreach( int i in arrInt )
Debug.WriteLine( i.ToString() );
// Use "for" to loop an arraylist
for( int i = 0; i < arrInt.Count; i++ )
{
int n = ( int ) arrInt[i];
Debug.WriteLine( n.ToString() );
}
5)缺点:
①不能修改枚举成员
②对集合进行删除操作
6)引用文献:
https://www.cnblogs.com/eniac12/p/4393978.html
https://blog.csdn.net/weixin_30361641/article/details/99807441
https://blog.csdn.net/weixin_33720956/article/details/90184585
二、C#中的数据类型
https://blog.csdn.net/sinat_39291423/article/details/77885749
C#的数据类型可以分为3类:数值类型,引用类型,指针类型。
1)数值类型
①整型(9种):
sbyte,byte,short,ushort,int,uint,long,ulong和char。
Sbyte: 代表有符号的8位整数,数值范围从-128 ~ 127
Byte: 代表无符号的8位整数,数值范围从0~255
Short: 代表有符号的16位整数,范围从-32768 ~ 32767
ushort: 代表有符号的16位整数,范围从-32768 ~ 32767
Int: 代表有符号的32位整数,范围从-2147483648 ~ 2147483648
uint: 代表无符号的32位整数,范围从0 ~ 4294967295
Long: 代表有符号的64位整数,范围从-9223372036854775808 ~ 9223372036854775808
Ulong: 代表无符号的64位整数,范围从0 ~ 18446744073709551615。
Char: 代表无符号的16位整数,数值范围从0~65535。
Char类型的可能值对应于统一字符编码标准(Unicode)的字符集。
Char类型与其他整数类型相比有以下两点不同之处:
a,没有其他类型到char类型的隐式转换。即使是对于sbyte,byte和ushort这样能完全使用char类型代表其值的类型, sbyte,byte和ushort到char的隐式转换也不存在。
b,char类型的常量必须被写为字符形式,如果用整数形式,则必须带有类型转换前缀。比如(char)10赋值形式有三种:
char chsomechar=“A”;
char chsomechar=“\x0065”; 十六进制
char chsomechar="\u0065 ; unicode表示法
字符型中有下列转义符:
1,'用来表示单引号
2,"用来表示双引号
3,\ 用来表示反斜杠
4, \0 表示空字符
5, \a 用来表示感叹号
6, \b 用来表示退格
7, \f 用来表示换页
8, \n 用来表示换行
9, \r 用来表示回车
10, \t 用来表示水平tab
11, \v 用来表示垂直tab
②浮点型
1.float
精确到小数点后面7位。
2.double
精确到小数点后面15位或16位。
备注:
如果二元操作中的其中一个操作数为浮点类型,那么另外一个操作数是整型或浮点类型,运算规则如下:
a,如果其中一个操作数是整型,则操作数被转换为另一个操作数的浮点数类型;
b,如果操作数之一为double,则另一操作数也被转换成double类型,运算以double类型的精度和取值范围进行,并且所得结果也为double类型;
c,否则,运算至少将以float类型的取值范围和精度进行,并且所得结果也为float型。
decimai类型(小数类型)
小数类型非常适用于金融和货币运算。数值范围从1.010 -28~7.9 10 28,精确到小数点后面28位。
布尔型:值为true或false。
没有标准能实现布尔类型和其他类型的转换。
bool result = 5 > 3 ? true : false;
枚举类型
**枚举类型的元素使用的类型只能是long,int,short,byte。**默认类型是int。默认第一个元素的值是0,每一个连续的元素按1递增。可以给元素直接赋值。如:
enum monthnames
{
January=1,
February,
march=31
};
可以强制定义其他类型,如:
enum monthnames : byte
{January ,
February,
March
};
public enum Gender
{
male,
female
//注意没有分号
}
**注意:
1)当我们在类中,使用枚举类型的时候,需要在类外and命名空间内声明枚举类型。
2)枚举类型的声明写法,需不需要“ ;”,哪里用到的是“ , ”
**
例如:
namespace _20210419
{
//枚举类型,性别判定,要在类外声明
//enmu-----枚举
public enum Gender
{
male,
female
//注意没有分号
}
public abstract class Bird
{
}
}
结构类型
结构类型也是一种值类型,使用它的目的是用于创建小型的对象,用以节省内存。
using System;
Struct IP //声明结构
{
public byte b1,b2,b3,b4;
}
Class test
{
public static void Main()
{
IP myIP;
myIP.b1=192;
myIP.b2=168;
myIP.b3=1;
myIP.b4=101;
Console.Write("{0}.{1}。", myIP.b1, myIP.b2);
Console.Write("{0}.{1}", myIP.b3, myIP.b4);
}
}
2)引用类型
引用类型包括类类型,接口类型,代表类型和数组类型。
1.类
类 类型定义了一种数据结构,这个数据结构中包含了数据成员(如常量,字段和事件等),函数成员(如方法,属性,索引,操作,构造函数和析构函数等)和嵌套 类型。支持继承。
2.对象![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/6382faa53ee1129a5a2c230f32468ecd.png)
对象类型是其他所有类型最终的基础类型。在C#中每一种类型都直接或者间接的源于object这个类类型。
3.字符串
字符串类型是直接从object中继承而来的密封类。String类型的值可以写成字符串文字的形式。
4.接口
见文章20210419
5.代表
代表引用一种静态的方法或者对象实例,引用该对象的实例方法。与其接近的是c/c++中的指针,但指针只能访问静态的函数,代表既能访问静态的方法,也能访问实例的方法。
6.数组
数组是包含一串变量的数据结构。
3)指针类型
当用unsafe修饰符标记时,C#允许在代码块的函数中使用指针变量。不安全代码或非托管代码是使用指针变量的代码块。
基本用法与C++类似
https://www.cnblogs.com/binlyzhuo/articles/1209097.html
https://www.nhooo.com/note/qa07zs.html
三、关于字符串总结学习
字符串一旦声明不再改变。所以只能通过索引来读取指定位置的char,不能对指定位置的char进行修改。
如果要对char进行修改,那么就必须创建一个新的字符串。
字符串的连接+;两边只要有一个是字符串类型,另一个也会被自动转换成字符串类型
两个字符串比较不区分大小写
https://blog.csdn.net/b4834988/article/details/101873040?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161925360816780265470528%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=161925360816780265470528&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-3-101873040.pc_search_result_hbase_insert&utm_term=c%23%E4%B8%AD%E5%AD%97%E7%AC%A6%E4%B8%B2
https://www.cnblogs.com/net-sky/p/9235913.html
https://www.cnblogs.com/zysbk/archive/2012/07/30/2615839.html
https://jingyan.baidu.com/article/db55b6094c633c4ba30a2f23.html
1.Replace(替换字符)
2.Remove(删除字符)
3.Substring(字符串提取)
4.Trim(清空空格)
5.ToLower(转换大小写)
6.IndexOf(获取指定的字符串的开始索引)
7.Equals(是否相等)
8.Split(拆分)
9.Contains(判断是否存在)
10.EndsWith,StartsWith(判断字符串的开始或结束)
11.Insert(字符串插入)
string str = "123@163.com";
int index = str.IndexOf('@'); // 返回3 从左向右第一个@
int index = str.LastIndexOf('3'); // 返回6 从右向左第一个3
string newStr = str.SubString(4); //从第4个字符开始截取 返回@163.com
==和Equals区别
==判断引用的地址,Equals判断值,c#会把所有值相同的字符串指向同一个地址,两者的结果没有区别
string[] strs = {"1","2","3"};
string newStr = string.Join("-",strs); //返回 1-2-3
string[] newStrs = newStr.Split('-'); //返回数组{"1","2","3"};
四、C#中的函数重载问题
函数重载
重载的定义:函数名相同,函数的参数列表不同(包括参数个数和参数类型),至于返回类型可同可不同。
重载是可使函数、运算符等处理不同类型数据或接受不同个数的参数的一种方法
https://blog.csdn.net/whc888666/article/details/83933217
1.方法重载:是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数
具体规范:
(1)函数名一定要相同。
(2)函数的参数表必须不同,包括参数的类型或个数
以此区分不同的方法体。
a.如果参数个数不同,就不管它的参数类型了。
b.如果参数个数相同,那么参数的类型必须不同。
(3)方法的返回类型、修饰符可以相同,也可不同。
public static int AddNumber(int num1,int num2)
{
return num1 + num2;
}
public static double AddNumber(int num1, int num2,int num3)
{
return num1 + num2;
}
public static double AddNumber(double num1, int num2)
{
return num1 + num2;
}
构造函数重载:
https://blog.csdn.net/qq_42672770/article/details/105436014
方法名和类名一样,没有返回值
(1)构造函数可以有参数,new对象的时候传递参数即可
(2)如果不指定构造函数,则类有一个默认的无参数构造函数
(3)如果指定了构造函数,则不再有默认的无参数构造函数
(4)如果需要五参数的构造函数,则需要自己来写
例子一:
class Chinese : Person
{
public Chinese (string name ,int age ,char sex) : base (name,age,sex ) //构造函数的继承调用
{ }
}
五、字段和属性的区分
字段:
存放数据
属性:
get
set
六、C#中构造函数的使用
构造函数的继承调用
例子二:
public Bird()//构造函数没有返回值
{
this.LegNumber = 2;//this是指创建出来的对象本身,
this._legs = new Leg[2];//创建两个对象数组,每一个成员是leg
this._legs[0] = new Leg();
this._legs[1] = new Leg();
this.chhibangnumber = 2;
this.Chibang1 = new Chibang[2];
this.Chibang1[0] = new Chibang();
this.Chibang1[1] = new Chibang();
this.BirdGender = Gender.female;
//C#中数组的定义
//C#中的数据类型
//int i = 1;
//double d = 1.213;
//float f = (float)3.14;
//decimal dd =(decimal) 11.11;
//bool b =true;
//float ff= (float)111.111;
//string name = "this";
//string name2 = name.Trim();//把字符串中的空格全部trim掉
//int ii = name.Substring(1);//取字符串中的字符
把关于字符串,关于数据类型,总结学习,全部找到
char c = 'A';
// int[] ii;//声明数组,此处仅仅声明
//创建数组,数组赋值方式有两种
//方法一
//ii = new int[4];
//ii[1] = 1;
//ii[2] = 2;
//ii[4] = 4;//其实是越界了,所以是错的
//方法二
int[]ii={1,2,3,4};//创建同时,进行赋值操作
}
public Bird(Gender gender):base()//函数的重载,base()在创建的时候先运行无参的构造函数
{
this.BirdGender = gender;
}
public Bird(int a) : base()//函数的重载,base()在创建的时候先运行无参的构造函数
{
//this.BirdGender = gender;
this.featherNumber = a;
this.Feathers = new Feather[featherNumber];
for (int i = 0; i < featherNumber; i++)
{
this.Feathers[i] = new Feather();
}
七、C#属性设置
只读,只写,读写,看逻辑关系,去判断
八、C#普通类和抽象类之间的关系
https://blog.csdn.net/qq_43477676/article/details/112125985
类和对象的关系:
类是一个抽象的概念,是具有相同属性和行为的一组对象的集合,用于创建对象;对象是类的具体实现,是客观真实存在的事物。
抽象类和普通类的区别:
抽象类是概念的抽象,而普通类是事物的抽象(成了概念),那么抽象类就不可以有实例了。
在这里插入图片描述
九、C#中面向对象的各种关系的描述
1)继承关系:
在C#中,基类就是被继承的类,也可以理解为父类,一个父类可以有多个子类。
但C#中一个字类,只能有一个父类
2)组合关系
它同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束,比如人和人的大脑。表现在代码层面,和关联关系是一致的,只能从语义级别来区分。
3)关联关系
关联体现的是两个类之间语义级别的一种强依赖关系,比如我和我的朋友,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。关联可以是单向、双向的。表现在代码层面,为被关联类
②程序改进
一、增加“leg”类
1)首先创建leg类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _20210419
{
public class Leg
{
public void Run()
{
Console.WriteLine("Hello World!Please put in the first number.");
}
}
}
2)其次,明白腿和鸟的关系,腿是一个普通类,不需要继承关系
3)在类中,写入,腿的数量,写入属性函数,可以设置为只读,因为大多鸟类都是只有两个腿的,不需要写入。
虽然,利用快捷方式建立的属性函数,包含读写,但是因为逻辑关系,我们有时候还是会进行舍取
private int legNumber;
public int LegNumber
{
get => legNumber;
//set => legNumber = value;
}
4)调用。
①在构造函数外声明
private Leg[] _legs;
②在构造函数中构造
public Bird()//构造函数没有返回值
{
this.LegNumber = 2;//this是指创建出来的对象本身,
this._legs = new Leg[2];//创建两个对象数组,每一个成员是leg
this._legs[0] = new Leg();
this._legs[1] = new Leg();
}
5)在program主程序中,运用
yanzi yanzii = (yanzi)eat;
yanzii._Legs[0].Run();
6)以下两行,逻辑错
//Leg leg = new Leg();
//leg.Run();
leg是普通类,但是另一个是组件类,腿不能无中生有独立存在,需要依附再鸟的对象上
二、使用接口实现“leg”跑的功能
接口需要基础才能实现内部函数的功能
固写代码为:
①在IRunable接口里写入:
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
namespace _20210419
{
public interface IRunable
{
public int RunningSpeed { get; set; }
public void Runable();
}
}
②在yanzi类加入
public class yanzi:Bird,IRunable//继承
public int RunningSpeed { get; set; }
public void Runable() {
Console.WriteLine("I can use IRunable.");
③在program主函数中进行调用。
yanzi yanzii = (yanzi)eat;
yanzii._Legs[0].Run();
yanzii.Chibang1[0].fly();
yanzii.Feathers[0].KeepWorm();
yanzii.Runable();
三、增加“chibang”(翅膀)类
与“leg”写法相一致
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _20210419
{
public class Chibang
{
public void fly()
{
Console.WriteLine("Hello chibang.");
}
}
}
四、增加“next”类(巢穴)
创建巢穴类,与鸟的关系是关联,可以独立存在,即可以new出来
代码如下:
①在“Nest”类中写入:
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
//--------------------创建巢穴类,与鸟的关系是关联,可以独立存在,即可以new出来-----------------
namespace _20210419
{
public class Nest
{
public void Live()
{
Console.WriteLine("Live");
}
}
}
②在Bird类中加入
private Nest _nest;
internal Nest BridNest { get => _nest; set => _nest = value; }//为什么写为BridNest,因为要防止命名1的重复
public Nest BuildNest()
{
this.BridNest = new Nest();
return this.BridNest;
}
③在program中加入:
//---------------------------------巢穴--------感受关联关系-----------------
Nest nest = new Nest();
// nest.Live();
//谁去住呢?谁和巢穴关联呢?Bird类要有一个属性去接受巢穴
yanzii.BridNest = nest;
yanzii.BridNest.Live();
五、使用接口实现“next”的居住功能
步骤如“使用接口实现“leg”跑的功能”
六、增加“egg”类 (蛋)
首先,想要增加,egg类
但是,我们会发现,只有雌鸟会下蛋
所以,我们要设置 性别,
设置函数,判断是否是雌性,即是否有下蛋能力
代码如下:
①egg类中:
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
namespace _20210419
{
public class Egg
{
public void Buring()
{
Console.WriteLine("egg");
}
}
}
②性别,可以用int=1,或0.判断,但是不规范。
为了让读取代码更加顺畅,我们设置枚举类,对性别进行设置。
其中,枚举类需要在类外声明,保证在类外也可以对性别进行判断。
并且需要改进构造函数
例如:在Bird中加入:
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
namespace _20210419
{
//枚举类型,性别判定,要在类外声明
//enmu-----枚举
public enum Gender
{
male,
female
//注意没有分号
}
public abstract class Bird //首先改为public,加上static类,就不能有构造函数,
{
private Gender _gender;
public Gender BirdGender { get => _gender; set => _gender = value; }
}
public Bird(Gender gender):base()//函数的重载,base()在创建的时候先运行无参的构造函数
{
this.BirdGender = gender;
}
public Egg CreateEgg()
{
if (this.BirdGender == Gender.female)
return new Egg();
else
return null;
}
}
③在program主函数中加入:
yanzii.CreateEgg();
调用函数。
③封装类库,改进程序
1)创建“类库”项目
2)引入我们项目中的类
3) 修改“类库”项目中,命名空间,改为和类库名一致
4)在菜单栏中,选择,生成解决方案
5)新建项目,控制台应用
6)“添加项目引用”,选择刚才建立的“解决方案”,一个dll文件
7)加入“using 自己类库名”
8)即可使用自己创建的类库
遇到的问题
internal的问题。
首先,我们不难得知,以下三点:
1) internal(内部):限定的是只有在同一程序集中可访问,可以跨类
2) protected(受保护):限定的是只有在继承的子类中可访问,可以跨程序集
3)protected internal:受保护“或”内部修饰符修饰成员,当父类与子类在同一个程序集中,internal成员可见。当父类与子类不在同一个程序集中,子类不能访问父类internal成员,而子类可以访问父类的ptotected internal成员,
即从当前程序集或从包含类派生的类型,可以访问具有访问修饰符 protected internal 的类型或成员。
其次,我们可以简单的理解:
internal,使得我们在编写自己的类库的时候,可以运行成功。
但声称dll文件后,在其他项目中引用就会报错了,这也不难发现,internal是保护在同一程序集中访问,当我们更换程序集就不可访问了。
最后,解决方式:
将internal改为public