C#高级
oop 是一种思维方式 一种看到问题解决问题的思考方式 着眼点在于找到一个能帮我们解决问题的实体 然后委托这个实体来帮我们解决问题
相反面向过程是自己一步一步去解决问题
类和对象 具有一定功能 能够帮忙解决特定问题的实体 就是对象
类 是一系列具有相同功能和特征的对象的集合
类的设计
语法 类名(标识符) 类体
using System;
namespace Program
{
class Person
{
//特征
private string name;
private int age;
//行为
void Eat() { }
void Sleep() { }
}
}
对象的实例化
//实例化一个对象
Person p = new Person();
p.Age = 28;
p.Name = "XX";
对象的内存分析 分配在堆上 大小取决类中的属性
class Program
{
static void Main(string[] args)
{
//实例化一个对象
Person p = new Person();
p.Age = 28;
p.Name = "XX";
p.Print();
Console.Read();
}
}
static 静态成员属于类 非静态属于对象的 需要用对象访问
构造方法无返回值 void都不行 方法名必须是类名 构造方法不能显示调用 实例化对象时候调用
作用 实例化一个对象(默认构造方法)私有构造方法(单例)
public Person(string _name)
{
Name = _name;
}
public Person(string _name, int _age):this(_name)
{
Age = _age;
}
静态构造方法 不允许有修饰符 必须无参数 用到类的时候执行(实例化类或者执行类静态方法) 先非静态构造函数 只会执行一次
static int refCnt = 0;
static Person()
{
refCnt = refCnt + 1;
}
属性访问控制器
readonly 只读 可以没有初始值 但是const需要有初始值 readonly可以在构造方法赋值 const一旦确定就不可以赋值
单例模式
设计模式 前人总结解决特定问题的解决问题方案模式
单例模式 在一个项目的不同模块中 获得对象永远都是一个对象
继承
如果多个类中 具有相同字段和方法 可以把相同的部分提取出一个新的类 新的类就是父类 其他的是子类 子类继承父类
子类拥有父类所有的字段和方法 不包括构造方法
一个类有多个子类 但只有一个父类 不支持多继承
一个类继承其他类的时候 也可以被其他类继承
类都会直接或者间接继承Object
一般对类修改或者扩展时候 要考虑到继承
继承中的构造方法 一个子类在实例化之前 需要先实例化从父类继承到的东西 需要使用父类的无参构造方法如果没有 会报错
也可以在子类中添加构造方法 调用基类的有参构造方法
class Animal
{
public string name;
public Animal(string _name)
{
this.name = _name;
}
}
class Dog:Animal
{
public Dog():base("")
{
}
}
访问权限修饰符
可以用来修饰 类 字段 属性 方法 作用用来描述修饰的内容访问的范围
public 用来修饰 类 字段 属性 方法 在整个解决方案中生效
interanl 用来修饰 类 字段 属性 方法 在整个项目都可以访问 类的默认权限是internal
protected 用来修饰 字段 属性 方法 能在当前类以及子类中使用 甚至可以在跨项目子类中使用
private 用来修饰 字段 属性 方法 只能在当前类中使用 字段 属性 方法默认访问权限就是private
protected interanl 用来修饰 字段 属性 方法 在当前项目 在跨项目中子类可访问
父类访问权限大于等于子类
public权限的类中 如果某个字段或者方法中使用了非public权限的类型 程序会要求一定要将用到的类型改为public
多态
向上转型 父类的引用可以指向子类的对象 子类类型转为父类类型 隐式转换 不需要额外操作 一定可以成功 向上转型后的对象不再能访问子类的属性 字段以及方法
向下转型 父类类型转换为子类类型 需要强制类型转换 可能会失败 如果向下转型失败 得到一个null
Animal a = new Dog();
Dog d = (Dog)(new Animal());
Dog s = new Animal() as Dog;
引用数据类型可以使用as
is关键字 判断某个对象的类型
as 强制类型转换 引用类型
方法隐藏重写
方法隐藏 使用关键字new
方法重写 override 虚函数virtual 虚函数可以被子类隐藏和重写 非虚函数只能被隐藏不能重写
涉及到向上转型 调用的方法隐藏还是父类的方法 重写的话是使用子类的实现
枚举 是一种类型
适用于某些取值范围有限的数据
【访问权限修饰符】关键字enum 枚举名
{
枚举值
}
public enum Season
{
Spring,
Summer,
Autumn,
Winter
}
虽然枚举中值可以一样 不推荐
枚举类型默认int 可以转为其他整形 一般与switch case结合使用
结构体:
和类基本是一样的
语法 【访问权限修饰符】struct 默认访问internal
相同点:包含字段属性方法 默认访问权限 都是通过关键字new实例化对象
最大不同 结构体对象是在栈 结构体值类型 类对象在堆 类引用类型
结构体不允许写无参构造函数 结构体有参构造必须要给所有字段赋值 结构体中始终包含一个public无参的构造方法
析构方法 结构体中不允许写析构函数
结构体只有一个父类Object 不能继承其他也不能被继承
当使用比较小的数据类型 可以使用结构体 C#所有基础类型都是结构体 就是值类型
静态类 由static修饰的类
不能实例化对象
静态类中不允许写非静态的成员
不能出现非静态构造函数
静态构造方法不能有访问权限和参数
静态类只能有一个父类 Object
作用:用来设计工具类
关键字 sealed 用来修饰类 方法 表示密封
密封类 不可被继承
方法不可被重写 方法前只能用在override的方法 不能在virtual中使用 只有方法被重写过才能密封
命名空间
是一个虚拟集合
中的元素只能是 类 结构体 枚举 接口等
可以防止类名重复 更好的管理类
using System;
using space1;
namespace space1
{
class A
{
}
class B
{
}
}
namespace space2
{
class A
{
}
class Program
{
public static void Main(string[] args)
{
//默认当前命名空间
A c = new A();
A a = new space2.A();
space1.A b = new space1.A();
B bb = new B();
}
}
}
命名空间名字可以重复 如果有多个名字一样的空间 是同一个命名空间
命名空间可以嵌套
namespace space3
{
//命名空间名字是space3.space3
namespace space3
{
}
}
运算符重载 通过特定的语法使得某些运算符具有特殊的功能
关键字 operator
struct Point
{
public double x;
public double y;
public Point(double _x,double _y)
{
x = _x;
y = _y;
}
public static Point operator +(Point p1,Point p2)
{
return new Point(p1.x + p2.x, p2.y + p2.y);
}
}
算术运算符全部可以重载
赋值运算符 全部不可以重载
关系运算符可以重载 一定要成对重载
逻辑运算符 && || 不能被重载
位运算符 ~可以被重载
抽象类
关键字abstract修饰的类
不能实例化对象
抽象类可以写静态成员 也可以写非静态成员
可以被其他类继承 也可以继承其他类
抽象方法
abstract修饰的方法
抽象方法只有声明没实现
抽象方法只能写在抽象类
abstract class Animal
{
public string name;
public Animal()
{
}
public abstract void Show();
}
非抽象类继承抽象类 要实现抽象方法 通过重写 使用new覆盖不行
class Dog:Animal
{
public override void Show()
{
}
}
抽象类使用场景 一种规范 用来约束所有子类的行为(必须要实现抽象类的方法)
接口
是一系列的规范
interface 不能实例化对象
接口中的方法不是抽象方法 接口中的方法不能有访问权限修饰符 接口中可以包含属性访问器
实现接口方法注意 必须为public方法 不能用override 抽象类可以实现接口方法 可以实现为抽象方法 接口中方法可以被实现为虚方法 为了让子类重写
一个类可以实现多个接口
接口命名一般I开头 区分类
interface IUSB
{
void Charge();
void TransportData();
}
//类实现接口
class Mouse : IUSB
{
public void Charge()
{
}
public void TransportData()
{
}
}
多态进阶 接口的引用可以指向实现类的对象 由实现类转为接口类型 向上转型 接口转实现类 向下转型
接口可以继承 可以多继承 子接口拥有父接口的所有规范
委托 一个方法的类型
using System;
//声明一个委托
delegate void MyDelegate();
class Program
{
public static void Main(string [] args)
{
//实例化一个委托需要一个方法名
//方法返回值参数需要和委托保持一致
//md指向一个方法 可以调用
MyDelegate md = new MyDelegate(Test);
md();
}
public static void Test()
{
}
}
//组合委托 连续技能使用
MyDelegate md = new MyDelegate(A);
md += B;
md -= A;
using System;
delegate void MyDelegate();
delegate int MyDelegateA(int a);
class Program
{
public static void Main(string [] args)
{
//匿名方法
//用关键字delegate代替方法名
MyDelegate md = delegate ()
{
Console.WriteLine("-------");
};
MyDelegateA ma = delegate (int x)
{
return x;
};
//lambda表达式
//=> 放在参数跟返回值之间
MyDelegate mb = ()=>
{
Console.WriteLine("-------");
};
MyDelegateA me= (int x)=>
{
return x;
};
//简化1 如果lambda方法体只有一个返回值 可以省略大括号 和 return
MyDelegateA mf = (int x) => x;
//简化2 如果lambda 参数列表 参数类型可以省略
MyDelegateA mg = (x) => x;
//简化2 如果lambda 参数列表只有一个 参数小括号可以省略
MyDelegateA mk = x => x;
}
}
泛型 可以传递类型 类似传参
泛型在类中应用
泛型的特点:
在一个命名空间可以存在两个类名相同的类 但两个类泛型不同
泛型只能用在当前类 不能被继承
using System;
//泛型命名
class Person<T>
{
public T t;
}
class Dog<T,M,D>
{
//一个类中不止一个泛型 不知道 tmd是什么 但是可以使用
//实例化对象的时候 确定类型
}
class Program
{
public static void Main(string[] args)
{
Person<string> p = new Person<string>();
p.t = "";
Person<int> p1 = new Person<int>();
p1.t = 1;
}
}
正则表达式
用来判断一个字符串是否符合一定的格式
无语法提示 就是一个字符串
^匹配字符串开头 $匹配字符串结尾
[]匹配一位字符中括号中的任意一位 [1-9][a-z]并起来[1-9a-z] [^1-9]可以是1-9之外的任何数字
+前面的一位字符连续出现了1次或多次
*前面的一位字符连续出现了0次或多次
?前面的一位字符连续出现了0次或1次
{m} 前面的字符连续出现了m次
{m,} 前面的字符至少连续出现了m次
{m,n}前面的字符出现了m-n次
\d 0-9
\D 非0-9
\ 字符串转义
. 通配符可以匹配任意字符
using System;
using System.Text.RegularExpressions;
class Program
{
public static void Main(string[] args)
{
Regex regex = new Regex("^[abcdedfH]ello World$");
Console.WriteLine(regex.IsMatch("Hello World"));
Console.Read();
}
}
反射
可以通过类名 成员方法名字 来对象实例化以及操作类成员
using System;
using System.Reflection;
class Person
{
public int a;
private int b;
public static int c;
private static int d;
public Person()
{
Console.WriteLine("实例化");
}
private Person(int a,string b)
{
Console.WriteLine("有参数");
}
public void ShowA() { }
private void ShowB() { }
public static void ShowC() { }
private static void ShowD() { }
public int Show(int a) { return a; }
private double Show(double a) { return a; }
}
class Program
{
public static void Main(string[] args)
{
//通过类名获取一个类型
//如果类在命名空间 需要加上命名空间
Type t = Type.GetType("Person");
//实例化一个对象 默认会使用public权限的无参构造方法来实例化
Object obj = Activator.CreateInstance(t);
//实例化一个对象 可以匹配任何无参的构造方法
Object obj1 = Activator.CreateInstance(t, true);
//实例化一个对象 默认会使用public权限的有参构造方法来实例化
Object obj2 = Activator.CreateInstance(t, 1, "2");
//实例化一个对象 使用非public权限的有参构造方法来实例化
Object obj3 = Activator.CreateInstance(t, BindingFlags.NonPublic | BindingFlags.Instance, null, 1, "2");
/*
* BindingFlag: 要访问的方法或者字段的权限描述 必须同时具备两个描述
* 1.要有访问成员的访问权限描述 要有要访问成员的归属
*/
//通过反射访问类中的字段
//1.访问非静态public
FieldInfo a = t.GetField("a");
a.SetValue(obj, 1); //赋值
Object aa = a.GetValue(obj); //获取
//2.访问非静态private
FieldInfo b = t.GetField("b", BindingFlags.NonPublic | BindingFlags.Instance);
b.SetValue(obj, 1); //赋值
Object bb = a.GetValue(obj); //获取
//3.访问静态public
FieldInfo c = t.GetField("c", BindingFlags.Public| BindingFlags.Static);
c.SetValue(null, 3);
Object cc = c.GetValue(null);
//4.访问静态private
FieldInfo d = t.GetField("c", BindingFlags.NonPublic | BindingFlags.Static);
d.SetValue(null, 3);
Object dd = c.GetValue(null);
//通过的反射或者类方法 无参
MethodInfo method0 = t.GetMethod("ShowD", BindingFlags.NonPublic | BindingFlags.Static);
method0.Invoke(null, null); //第一个参数谁在调用 第二个是方法参数
//带参数方法
MethodInfo method1 = t.GetMethod("Show", BindingFlags.NonPublic | BindingFlags.Instance,null,new Type[] { typeof(int) },null);
Object ret = method0.Invoke(obj, new object[] { 1}); //第一个参数谁在调用 第二个是方法参数
}
}