初级.Net工程师必备技能

前端基础:

    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 表示有传入参数int,string无返回值的委托

   Action 表示有传入参数int,string,bool无返回值的委托

    Action 表示有传入4个int型参数,无返回值的委托

  Action至少0个参数,至多16个参数,无返回值。

例:

        public void Test(Action action,T p)

        {

            action(p);

        }

(3). Func

  Func是有返回值的泛型委托

  Func 表示无参,返回值为int的委托

  Func 表示传入参数为object, string 返回值为int的委托

  Func 表示传入参数为object, string 返回值为int的委托

  Func 表示传入参数为T1,T2,,T3(泛型)返回值为int的委托

  Func至少0个参数,至多16个参数,根据返回值泛型返回。必须有返回值,不可void

例:   

        public int Test(Funcfunc,T1 a,T2 b)

        {

            return func(a, b);

        }

(4) .predicate

  predicate 是返回bool型的泛型委托

  predicate 表示传入参数为int 返回bool的委托

  Predicate有且只有一个参数,返回值固定为bool

例:public delegate bool Predicate (T obj)

 

 

事件的实例

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);  //启动异步线程

初级.Net工程师必备技能_第1张图片

初级.Net工程师必备技能_第2张图片

 

线程同步: 是指在某一时刻只有一个线程可以访问变量 。

  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 MethodAsync();//有返回值的异步方法

private async Task MethodAsync();//无返回值的异步方法

private async void btnOk_Click();//异步事件处理程序

await是一个运算符,它表示等待异步执行的结果。也可以理解为await运算符实际上是对方法的返回值进行操作,也就是对Task进行操作,而不是对方法本身进行操作。还有一点要注意,await是一定要放在异步方法的内部,如果没有放在内部的话,VS会自动报错。以下是asyncawait使用的例子: 

    private async void button5_Click(object sender, EventArgs e)
    {
      Task a = Method1Async();
      //此处可继续执行其他代码
      await a;//等待任务a完成
      Task b = Method2Async();
      //此处可继续执行其他代码
      int c = await b;//等待任务b完成,且可以拿到任务b的返回值
    }

    Task Method1Async();
    async Task Method2Async()
    {
      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的相互转化时需要用到反射;

 

你可能感兴趣的:(初级.Net工程师必备技能)