一、C#中的访问修饰符
public : 公共的、公开的
private: 私有的、只能在当前类的内部使用
protected: 受保护的、只能在当前类的内部和该类的子类中访问
internal: 只能在当前程序集(项目)中访问
protected internal :protected + internal
1):能够修饰类的访问修饰符只有两个:public / internal
internal: 只能在当前项目中使用
public :在别的项目也可以使用,但需要引用该项目,并且带入命名空间(using 命名空间)
注意: 在当前项目中,两个修饰符访问权限一样
2):可访问性不一致 : 子类的访问权限不能高于父类
因为子类会继承父类的成员,这样子类会暴露父类的成员
二、简单工厂设计模式
1、设计模式: 设计某个项目的一种方式(规划)。比如:盖楼前的图纸
经典的C#设计模式:23个
2、简单工厂设计模式
例题:有一个工厂要可以生产Dell/Lenovo/Acer/IBM笔记本电脑,客户下订单前不确定要生产哪种笔记本。但是工厂不能停工,需要生产。
解题思路:因不确定性高,所以不能用虚方法,只能用抽象父类,创建一个抽象父类,然后用子类给父类赋值,在主函数中写一个函数,要求调入笔记本名,相应返回一个子类
先创建一个抽象父类(实现多态):
public abstract class NoteBook
{
public abstract void SayHello();
}
然后创建产品的子类对象:
public class Dell : NoteBook
{
public override void SayHello()
{
Console.WriteLine("戴尔笔记本电脑,我是美国公司");
}
}
public class Lenovo : NoteBook
{
public override void SayHello()
{
Console.WriteLine("联想笔记本电脑,我是中国公司");
}
}
public class Acer : NoteBook
{
public override void SayHello()
{
Console.WriteLine("宏碁笔记本电脑,我是台湾公司");
}
}
public class IBM : NoteBook
{
public override void SayHello()
{
Console.WriteLine("IBM笔记本电脑,我是日本公司");
}
}
写一个核心方法:
//模拟笔记本生产的过程
/// <summary>
/// 简单工厂的核心,根据用户的输入创建相应对象赋值给父类
/// </summary>
/// <param name="brands"></param>
/// <returns></returns>
public static NoteBook GetNoteBook(string brands)
{
NoteBook nb = null; //新建一个父类对象,用来准备接收不同子类的赋值
switch(brands)
{
case "Lenovo": nb= new Lenovo(); break;
case "Acer": nb= new Acer(); break;
case "IBM": nb= new Lenovo(); break;
case "Dell": nb= new Dell(); break;
}
return nb;
}
然后在主函数里调用:
Console.WriteLine("请输入需要的笔记本品牌:");
string brands = Console.ReadLine();
NoteBook nb = GetNoteBook(brands);
nb.SayHello(); //调用相应的子类的方法
三、值类型和引用类型
1、值类型:int、double、char、decimal、bool、enum、struct ----存在栈上
值传递:
int n1 = 10;
int n2 = n1; //将n1的值赋值给n2
n2 = 20;
Console.WriteLine(n1);
Console.WriteLine(n2);
//原理:n1和n2在栈中开辟了两个空间,各自赋值,两个值互不影响。
ref的实现原理: ref可以实现将值类型默认的值传递改成地址传递(引用传递)!
2、引用类型:string、数组、自定义类、集合、object、 接口 -----存在堆上
引用传递(地址传递):
Person p1 = new Person();
p1.Name = "张三";
Person p2 = p1;
p2.Name = "李四";
p1.Name = "abc";
Console.WriteLine(p1.Name); //结果“李四”
Console.WriteLine(p2.Name); //结果“李四”
//原理:new Person对象存在堆中,p1储存的是此对象在栈上的地址
// p2 = p1 实际上只是把p1的值(对象在堆中的地址)赋值给了p2,实际上是同一个对象
//所以不管给哪个赋值,另一个会跟着改变
特殊的引用传递:
//字符串的不可变性:每次赋值都会重新开一块空间
string s1 = "张三";
string s2 = s1;
s2 = "李四";
Console.WriteLine(s1); //结果“张三”
Console.WriteLine(s2); //结果”李四“
四、序列化和反序列化 : 作用 : 传输数据 ----- 网络传输时只能传输二进制
1、序列化 : 将对象转换为二进制
1)只有在类前面加上: [Serializable] 的类创建的对象,才能被序列化,并且此类不能被继承
2)创建一个序列化对象:
//用序列化的类创建一个对象
BinaryFormatter bf = new BinaryFormatter();
3)调用对象的方法完成序列化: bf.Serialize(stream, object) 第一个参数为文件流,第二个参数为要序列化的对象
//创建一个文件流
FileStream fWrite = new FileStream(@"C:\Users\tufeiax\Desktop\111.txt", FileMode.OpenOrCreate, FileAccess.Write);
//用序列化的类创建一个对象
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fWrite,p); //自动调用fWrite.Write方法,将序列化后的对象传入路径下的文件中
fWrite.Close();
2、反序列化 : 将二进制转化为对象
1)创建一个文件流:
FileStream fRead = new FileStream(@"C:\Users\tufeiax\Desktop\111.txt", FileMode.OpenOrCreate, FileAccess.Read);
//用序列化的类创建一个对象
2)//用序列化的类创建一个对象
BinaryFormatter bf = new BinaryFormatter();
3)//反序列化,自动调用fRead.Read方法,读取路径文件,创建一个该类的对象,将读取的数据强转成此类返回
Person p = (Person)bf.Deserialize(fRead);
五、部分类: partial class
可同时对该类进行编程(几人同时写代码时方便合并这个类) ---但几个部分类的成员不能有同名
六、密封类:sealed class
特征:不能作为父类 (顾名思义,密封类是为了不被外界提取,用来保密) ,但是可以继承别人
七、重写ToString()方法:
不管什么情况下,所有对象的ToString方法,返回值是该类的完整调用路径(字符串)
ToString方法是object的虚方法,所有对象都可以重写它,并返回所需要的字符串
public class Person
{
public override string ToString()
{
return "Hello World";
}
}