- 1.委托,lambda表达式
- 2.泛型
- 3.特性,反射
特性,类似于标签,继承于Attribute基类,
利用 [] 注解加上标签,
通过程序集反射,获取当前程序集中的所有类型,并且通过GetCustomAttributes的方法获取特定特性的类集合
class HeroAttribute : Attribute
types = Assembly.GetExecutingAssembly().GetTypes(). Where(t => t.GetCustomAttributes(typeof(HeroAttribute),false).Any()).ToList();
class SkillAttribute : Attribute
//创建当前选中的英雄的对象实例
Type selectHeroType = types[listBox1.SelectedIndex]; heroType = Activator.CreateInstance(selectHeroType);
//获取该英雄的所有技能
var skillMethods = selectHeroType.GetMethods(). Where(m => m.GetCustomAttributes(typeof(SkillAttribute), false).Any()).ToList();
4.进程线程,thread,task
- 进程是操作系统执行的最小单元,是进程中的基本执行单元,是操作系统分配CPU时间的基本单位
- 一个进行可以有一个或多个线程,一个线程只属于一个进程
- 进程有自己单独的系统资源进行处理,而线程没有单独的资源,轮到它来执行时,它获得所属线程的系统资源进行处理,执行完之后资源分配到下一个线程,这个看系统对线程池的调度情况
- Thread.Start(),多线程执行时优先用task,定义一个List<Task>集合,每个Task执行一个任务,同步进行,可以增加程序的效率,如果需要等到所有的Task执行完之后才走下一步,那么就可以使用whenAll方法
private void button5_Click(object sender, EventArgs e)
{
List<Task> tasks = new List<Task>();
tasks.Add(Task.Run(() =>
{
Thread.Sleep(3000);
MessageBox.Show("上衣洗好了");
}));
tasks.Add(Task.Run(() =>
{
Thread.Sleep(5000);
MessageBox.Show("裤子洗好了");
}));
Task.WhenAll(tasks).ContinueWith(t => {
MessageBox.Show($"衣服都洗好了,可以晾了");
});
}
5.面相对象,封装,继承,多态
- a.隔离变化,降低耦合度
- b.抽取公共行为作为接口或虚方法,具体的功能实现放在继承类中
- c.重复的代码抽取出来作为单独的方法
6.虚函数,接口
- 虚函数一般定义为类的固有行为,就是继承于该类的所有子类都必须要实现的方法,比如一片门的开启和关闭两个动作,这种就用虚函数来定义
- 接口一般来定义一些扩展性的行为,比如一片安全门,它在开和关的基础功能上,还有指纹解锁和报警等功能,这种就抽象成接口来处理。
7.设计模式,工厂模式等
8.BackgroundWorker后台组件:
- doWork事件执行逻辑,doWork中可以实时传下逻辑数据到主线程UI上,传递到 ProgressChanged事件中的e.UserState
- progressChanged事件跨线程直接操作主线程UI获取一些状态信息
- RunWorkerCompleted事件是执行完之后的处理,显示处理结果等
9 .net5发布
- 编辑里面可以选择依赖环境或者独立,最好选择独立,就不需要在客户端的电脑上按照.net core环境就可以直接运行因为发布包里面自带了相关的依赖类库
- 现在都倾向于.Net Core ,因为可以避免所有程序exe依赖一个本台电脑的一个环境配置,.net core 打包出来的可以自带相应的环境
- .net standard 是.net core 和.net Framework的基础,类似于接口是实现类的关系
- .net core是跨平台的,可以发布到linux,IOS 等环境上;.net framework只能运行在window环境上
10. NuGet知识点
在线下载依赖,使用时考虑更新频率,下载次数,是否收费等
a.命令行安装方式,在官网www.nuget.org上搜索到之后,直接拷贝到网页上的安装命令 到程序包管理控制台里面运行
b.图形界面安装,项目右键->管理Nuget程序包->浏览里面搜索,然后选择版本进行安装
c.卸载:把安装命令的Install改成UnInstall ;或者右键->管理Nuget程序包->已安装里面进行卸载
11.异步编程
- 异步方法,返回值定义为Task<T>,如果不需要返回值,则为无泛型的Task
- 方法需要加签名需要 async ,方法里面用到的异步逻辑需要加上 await ,如果不加await,会导致前面的异步还没执行完,就走到下面的逻辑,下方的逻辑如果需要使用到前面异步方法的资源时,程序就会报错,如果后面的方法不需要等下前面异步执行,就可以不加await
- 自己编写一个await的异步方法,HttpClient下载网页内容(HttpClient实现了Dispose虚方法,所以最好最外层包一个using,用于资源的释放)
- 异步操作前面加async虽然对单个线程来说相当于同步了,但是它不会阻塞主线程,是多线程的同步
- 如果调用了异步方法的方法体不支持async,那么可以将里面的逻辑加上 .Result()或者.Wait(),去掉await。但是注意,这样会阻塞主线程,有死锁的风险;
- 从反编译工具中可以看出,一个async方法会被拆分成多个状态,分多次调用,如果里面有多个await的话
- await调用的等待期间,.NET 运行时会将当前线程返回给线程池,等到异步方法执行完毕之后,.NET运行时会在线程池中调出一个空闲的线程来执行后续的代码逻辑(前后两个线程有可能相同,也有可能不同,取决于线程池的调度情况,如果异步方法执行的很快,就可能相同)
Console.WriteLine("1.当前线程ID:" + Thread.CurrentThread.ManagedThreadId);
using (HttpClient httpClient = new HttpClient())
{
string html = await httpClient.GetStringAsync("https://www.baidu.com/");
}
Console.WriteLine("2.当前线程ID:" + Thread.CurrentThread.ManagedThreadId);
StringBuilder sbtxt = new StringBuilder();
string fileName = @"C:\Users\liyumin\Desktop\oracle语句\liyumin.txt";
for (int i = 0; i < 10000; i++)
{
sbtxt.Append("liyuminliyuminliyuminliyuminliyumin");
}
await File.WriteAllTextAsync(fileName, sbtxt.ToString());
Console.WriteLine("3.当前线程ID:" + Thread.CurrentThread.ManagedThreadId);
可以看出,执行两次await 的异步方法后,当前线程同时也换了2次
- 异步方法并不等于就是多线程,加了async的方法不一定就会在新的线程中运行,需要手动加上await的异步逻辑处理,才会采用新的线程来处理,如下图,CaclAsync里面的需要手动改成启动新线程的方法,才会在新的线程中执行
static async Task Main(string[] args)
{
Console.WriteLine("1.当前运行线程的ID:"+Thread.CurrentThread.ManagedThreadId);
await CaclAsync();
Console.WriteLine("2.当前运行线程的ID:" + Thread.CurrentThread.ManagedThreadId);
}
private static Task<int> CaclAsync()
{
return Task.Run(() =>
{
int result = 0;
for (int i = 0; i < 100; i++)
{
result += i * i;
}
return result;
});
}
可以看出前后的线程ID已经不一致了
- 方法签名的async 和里面的await是成对出现的,如果异步方法里面去掉了await,那么方法名称的async也就不需要了,一般在方法里面,如果不需要对Task<TResult>里面的泛型返回值进行处理,就可以直接返回Task<TResult>,反之则就需要加上await和async对。
//可以不需要await和async的处理
private static Task<int> CaclAsync()
{
return Task.Run(() => {
int result = 0;
for (int i = 0; i < 100; i++)
{
result += i * i;
} return result;
});
}
//需要加await和async的处理
static async Task<string> Read2Async()
{
string s =await File.ReadAllTextAsync("");
return s + "xxxxxx";
}
- 不推荐用Thread.Sleep(),而是推荐用 await Task.Delay,因为Thread.sleep是让UI线程睡眠,如果是 winform程序的话,界面就会卡住无法操作,而用task.Delay()就不会操作主线程,而是延迟下一个异步线程操作的到来,所以如果要实现界面不卡死时,可以在控件的事件方法上加上async。
- Thread.sleep相当于让主线程卡住不动,而Task.Delay()相当于当处理逻辑代码卡住不动,线程还是该干啥干啥
- CancellationToken的使用,可以自定义在何种情况下取消异步方法的执行,有自己手动设置取消的IsCancellationRequested 和调用系统内置的抛出异常的操作ThrowIfCancellationRequested()