前端基础:
Html、CSS、JS、JQuery、ajax、PS
前段框架:
UI框架:EasyUI、Bootstrap
JS框架:Vue.js、Node.js
C#基础:
委托(匿名方法)、事件、多线程、异步、接口、泛型、反射、特性
C#高级:
MVC、API、三层、EF、Lingq、Lambda、身份认证、Http、Socket
.Net Core:
中间件、注册服务、发布和部署
数据库:
CodeFrist、增删查改、视图、存储过程、事务、数据库优化
版本管理工具:
SVN、Git
加分项:
代码优化、数据库优化、服务器优化、网络通信技术、串口通信技术
1.委托的声明
(1). delegate
delegate我们常用到的一种声明
Delegate至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型。 例: public delegate int MethodtDelegate(int x, int y);
表示有两个参数,并返回int型。
(2). Action
Action是无返回值的泛型委托。
Action 表示无参,无返回值的委托
Action
Action
Action
Action至少0个参数,至多16个参数,无返回值。
例:
public void Test
{
action(p);
}
(3). Func
Func是有返回值的泛型委托
Func
Func
Func
Func
Func至少0个参数,至多16个参数,根据返回值泛型返回。必须有返回值,不可void
例:
public int Test
{
return func(a, b);
}
(4) .predicate
predicate 是返回bool型的泛型委托
predicate
Predicate有且只有一个参数,返回值固定为bool
例:public delegate bool Predicate
事件的实例
static void Main(string[] args)
{
Heater heater = new Heater();
Alarm alarm = new Alarm();
heater.Boiled += alarm.MakeAlert; //注册方法
heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法
heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册
heater.Boiled += Display.ShowMsg; //注册静态方法
heater.BoilWater(); //烧水,会自动调用注册过对象的方法
Console.ReadKey();
}
public class Heater // 热水器
{
private int temperature;
public string type = "RealFire 001"; // 添加型号作为演示
public string area = "China Xian"; // 添加产地作为演示
//声明委托
public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e);
public event BoiledEventHandler Boiled; //声明事件
// 定义BoiledEventArgs类,传递给Observer所感兴趣的信息
public class BoiledEventArgs : EventArgs
{
public readonly int temperature;
public BoiledEventArgs(int temperature)
{
this.temperature = temperature;
}
}
// 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
protected virtual void OnBoiled(BoiledEventArgs e)
{
if (Boiled != null)
{ // 如果有对象注册
Boiled(this, e); // 调用所有注册对象的方法
}
}
public void BoilWater() // 烧水。
{
for (int i = 0; i <= 100; i++)
{
temperature = i;
if (temperature > 95)
{
//建立BoiledEventArgs 对象。
BoiledEventArgs e = new BoiledEventArgs(temperature);
OnBoiled(e); // 调用 OnBolied方法
}
}
}
}
public class Alarm // 警报器
{
public void MakeAlert(Object sender, Heater.BoiledEventArgs e)
{
Heater heater = (Heater)sender; //这里是不是很熟悉呢?
//访问 sender 中的公共字段
Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature);
Console.WriteLine();
}
}
public class Display // 显示器
{
public static void ShowMsg(Object sender, Heater.BoiledEventArgs e)
{
Heater heater = (Heater)sender; //静态方法
Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
Console.WriteLine();
}
}
当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行是同步方法;当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调用者不用等待该方法执行完毕为异步方法。异步的好处在于非阻塞(调用线程不会暂停执行去等待子线程完成),因此我们把一些不需要立即使用结果、较耗时的任务设为异步执行,可以提高程序的运行效率。
C#中的线程分为前台线程和后台线程,线程创建时不做设置默认是前台线程。即线程属性Thread.IsBackground = false应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
ThreadStart方式实现多线程
Thread thread = new Thread(new ThreadStart(方法名));
thread.Start();
使用ParameterizedThreadStart委托方式实现多线程
//绑定带参数的异步方法
Thread thread = new Thread(newParameterizedThreadStart(方法名));
Person person = new Person();
person.Name = "Jack";
person.Age = 21;
thread.Start(person); //启动异步线程
线程同步: 是指在某一时刻只有一个线程可以访问变量 。
c#为同步访问变量提供了一个非常简单的方式,即使用c#语言的关键词Lock,它可以把一段代码定义为互斥段,互斥段在一个时刻内只允许一个线程进入执行,实际上是Monitor.Enter(obj),Monitor.Exit(obj)的语法糖。在c#中,lock的用法如下:
lock (this)
lock (obj) { dosomething... }obj代表你希望锁定的对象,注意一下几点:
1. lock不能锁定空值 ,因为Null是不需要被释放的。
2.不能锁定string类型 ,虽然它也是引用类型的。因为字符串类型被CLR“暂留”,这意味着整个程序中任何给定字符串都只有一个实例,具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。
3.值类型不能被lock ,每次装箱后的对象都不一样 ,锁定时会报错
4.避免锁定public类型 如果该实例可以被公开访问,则 lock(this) 可能会有问题,因为不受控制的代码也可能会锁定该对象。
推荐使用 private static readonly类型的对象,readonly是为了避免lock的代码块中修改对象,造成对象改变后锁失效。
private static readonly object locker = new object();
Invoke:在“拥有控件的基础窗口句柄的线程” 即在本例的主线程上执行委托,这样就不存在跨线程访问了 ,因此还是线程安全的。
线程池
上面介绍了介绍了平时用到的大多数的多线程的例子,但在实际开发中使用的线程往往是大量的和更为复杂的,这时,每次都创建线程、启动线程。从性能上来讲,这样做并不理想(因为每使用一个线程就要创建一个,需要占用系统开销);从操作上来讲,每次都要启动,比较麻烦。为此引入的线程池的概念
ThreadPool线程池中包含有两个静态方法可以直接启动工作者线程:
一为 ThreadPool.QueueUserWorkItem(WaitCallback)
二为 ThreadPool.QueueUserWorkItem(WaitCallback,Object)
先把WaitCallback委托指向一个带有Object参数的无返回值方法,再使用 ThreadPool.QueueUserWorkItem(WaitCallback) 就可以异步启动此方法,此时异步方法的参数被视为null 。
static void Main(string[] args){
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod1), new object()); //参数可选
Console.ReadKey();
}
public static void ThreadMethod1(object val) {
for (int i = 0; i <= 500000000; i++){
if (i % 1000000 == 0) {
Console.Write(Thread.CurrentThread.Name);
}
}
}
private async Task
private async Task MethodAsync();//无返回值的异步方法
private async void btnOk_Click();//异步事件处理程序
await是一个运算符,它表示等待异步执行的结果。也可以理解为await运算符实际上是对方法的返回值进行操作,也就是对Task
private async void button5_Click(object sender, EventArgs e)
{
Task a = Method1Async();
//此处可继续执行其他代码
await a;//等待任务a完成
Task
//此处可继续执行其他代码
int c = await b;//等待任务b完成,且可以拿到任务b的返回值
}
Task Method1Async();
async Task
{
await Task.Delay(100);
return 1;
}
await和同步程序设计最大的不同之处是:异步等待任务完成的时候,在不会继续执行后面的代码时,也不会影响接口的操作。在.NET提供的类中,异步方法都是约定用Async作为后缀,这样可以很清楚的知道这个方法是异步方法还是同步方法。
抽象类:
1、抽象类使用abstract修饰;
2、抽象类不能实例化,即不能使用new关键词来实例化对象;
3、含有抽象方法(使用abstract关键词修饰的方法)的类是抽象类,必须使用abstract关键词修饰;
4、抽象类可以含有抽象方法,也可以不包含抽象方法,抽象类中可以有具体的方法;
5、如果一个子类实现了父类(抽象类)的所有抽象方法,那么该子类可以不必是抽象类,否则就是抽象类;
6、抽象类中的抽象方法只有方法体,没有具体实现;
界面:
1、接口使用interface修饰;
2、界面不能被实例化;
3、一个类只能继承一个类,但是可以实现多个接口;
4、接口中方法均为抽象方法;
5、接口中不能包含实例域或静态方法(静态方法必须实现,接口中方法是抽象方法,不能实现);
C#接口(interface)用来定义一种程序的协议。实现接口的类或者结构要与接口的定义严格一致。有了这个协议,就可以抛开程序设计语言的限制(理论上)。C#接口可以从多个基接口继承,而类或结构可以实现多个接口。C#接口可以包含方法、属性、事件和索引器。接口本身不提供它所定义的成员的实现。接口只指定实现该接口的类或接口必须提供的成员。
interface IMyExample
{
int this[int index] { get ; set ; } //索引器
event EventHandler Even ; //事件
void Find(int value) ; //方法
string Point { get ; set ; } //属性
}
泛型(Generic)
允许您延迟编写类或方法中的程序设计元素的数据类型的规范,直到实际在程序中使用它的时候。换句话说,泛型允许您编写一个可以与任何数据类型一起工作的类或方法。您可以通过数据类型的替代参数编写类或方法的规范。当编译程序遇到类的构造函数或方法的函数调用时,它会生成代码来处理指定的数据类型。
泛型限定条件:public class CacheHelper<T> where T:new()
T:结构(类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型)
T:类 (类型参数必须是引用类型,包括任何类、接口、委托或数组类型)
T:new() (类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时new() 约束必须最后指定)
T:<基类名> 类型参数必须是指定的基类或派生自指定的基类
T:<接口名称> 类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
1、为什么需要反射:https://www.cnblogs.com/landeanfen/p/4642814.html
最初使用反射的时候,作为小菜总是不理解,既然可以通过new 一个对象的方式得到对象,然后通过对象去调用属性和方法,那么为什么还需要反射去调用呢?后来使用多了发现这就是一个先绑定还是后绑定的问题,很多初使用反射的开发人员通常都会有类似这种疑虑:既然在开发时就能够写好代码,干嘛还放到运行期去做,不光繁琐,而且效率也受影响。博主觉得主要是适用性的问题,如果你的系统没有那么高的扩展性和灵活性要求,你大可不必考虑反射。但在架构设计时,很多东西都需要考虑复用性,并且在某些特定的场景下你得不到具体的类时,你就必须用到反射。博主总结了下自己使用过的反射场景:
(1)有时不知道具体的类型,可以通过dll去得到类的对象;
(2)某些特殊方法,传过来的是泛型类,需要通过反射处理某些特殊的业务;
(3)通用方法DataTable和List