C#委托·特性·linq查询.线程

目录

 

泛型

泛型类

泛型方法

委托

委托基本知识

泛型委托

Action委托

Func委托

多播委托

匿名函数

lambda表达式

观察者设计模式(事件)

LINQ查询语句

反射和特性

特性

线程

委托创建线程

Thread创建线程

线程池

任务

连续任务

任务层次结构


泛型

泛型类

      class ClassA<T,A> 
        {
          //T代表一个数据类型,当使用classA进行构造的时候,需要制定T的类型
          private T a;
          private T b;
          private A c;

          public ClassA(T a, T b )
          {
              this.a = a;
              this.b = b;
          }

          public string  GetSum()
          {
            
              return a +""+ b;
          }
        }

     var o1 = new ClassA<int>(12,34);//当我们利用泛型类构造的时候,需要制定泛型的类型
     string s = o1.GetSum();
     Console.WriteLine(s);

泛型方法

 public static string GetSum<T,T2,T3,T4>(T a, T b)
        {
            return a + "" + b;
        }
  Console.WriteLine(GetSum<int,int,int,int>(12,34)); 

委托

委托基本知识

 private delegate string GetAString();//定义了一个委托类型,这个委托类型的名字叫做GetAString
  static void Main(string[] args)
        {
            int x = 40;
            string s = x.ToString();//tostring 方法用来把数据转换成字符串
            Console.WriteLine(s);
            //使用委托类型 创建实例
            GetAString a = new GetAString(x.ToString);//a指向了x中的tostring方法
            GetAString a = x.ToString;

            string s = a();//通过委托实例去调用 x中的tostring方法
            string s = a.Invoke();//通过invoke方法调用a所引用的方法
            Console.WriteLine(s);//通过委托类型是调用一个方法,跟直接调用这个方法 作用是一样的
            //实例2 使用委托类型作为方法的参数
            PrintString method = Method1;
            PrintStr(method);
            method = Method2;
            PrintStr(method);
            Console.ReadKey();
        }

        private delegate void PrintString();

        static void PrintStr( PrintString print )
        {
            print();
        }

        static void Method1() {
            Console.WriteLine("method1");
        }

泛型委托

    //泛型委托
    public delegate int Delcompare<T>(T n1,T n2);
    person[] people = { new person() {Age=12 },new person() { Age=22} };
     string max = GetMax(names, Compare2);
     person p = GetMax(people, Compare3);

    //返回任意数组中的最大值
        public static T GetMax<T>(T[] nums, Delcompare<T> del)//传入一个委托函数,就是比较方法
        {
            T max = nums[0];
            for (int i = 0; i < nums.Length; i++)
            {
                if (del(max, nums[i]) < 0)
                {
                    max = nums[i];
                }
            }
            return max;
        }
        public static int Compare1(int n1, int n2)
        {
            return n1 - n2;
        }
        public static int Compare2(string n1, string n2)
        {
            return n1.Length - n2.Length;
        }
        public static int Compare3(person n1, person n2)
        {
            return n1.Age - n2.Age;
        }
        public class person
        {
            public int Age
            {
                get;
                set;
            }
        }

Action委托

        static void PrintString()
        {
            Console.WriteLine("hello world.");
        }

        static void PrintInt(int i)
        {
            Console.WriteLine(i);
        }

        static void PrintString(string str)
        {
            Console.WriteLine(str);
        }

        static void PrintDoubleInt(int i1, int i2)
        {
            Console.WriteLine(i1+i2);
        }
            Action a = PrintString;//action是系统内置(预定义)的一个委托类型,它可以指向一个没有返回值,没有参数的方法
            Action<int> a=PrintInt;//定义了一个委托类型,这个类型可以指向一个没有返回值,有一个int参数的方法
            Action<string> a = PrintString;//定义了一个委托类型,这个类型可以指向一个没有返回值,有一个string参数的方法 在这里系统会自动寻找匹配的方法
            Action<int, int> a = PrintDoubleInt;
            a(34, 23);
            Console.ReadKey();
            //action可以后面通过泛型去指定action指向的方法的多个参数的类型 ,参数的类型跟action后面声明的委托类型是对应着的

Func委托

        static int Test1()
        {
            return 1;
        }

        static int Test2(string str)
        {
            Console.WriteLine(str);
            return 100;
        }

        static int Test3(int i, int j)
        {
            return i + j;
        }
             Func<int> a = Test1;//func中的泛型类型制定的是 方法的返回值类型
             Console.WriteLine(a());
             Func<string, int> a = Test2;//func后面可以跟很多类型,最后一个类型是返回值类型,前面的类型是参数类型,参数类型必须跟指向的方法的参数类型按照顺序对应
            Func<int, int, int> a = Test3;//func后面必须指定一个返回值类型,参数类型可以有0-16个,先写参数类型,最后一个是返回值类型
            int res = a(1, 5);
            Console.WriteLine(res);
            Console.ReadKey();

多播委托

前面使用的委托都只包含一个方法的调用,但是委托也可以包含多个方法,这种委托叫做多播委托。

使用多播委托就可以按照顺序调用多个方法,多播委托只能得到调用的最后一个方法的结果,一般我们把多播委托的返回类型声明为void。

多播委托包含一个逐个调用的委托集合,如果通过委托调用的其中一个方法抛出异常,整个迭代就会停止。

        static void Test1()
        {
            Console.WriteLine("test1");
            //throw new Exception();
        }

        static void Test2()
        {
            Console.WriteLine("test2");
        }
 //多播委托
            Action a = Test1;
            //a = Test2;
            a += Test2;//表示添加一个委托的引用 
            //a -= Test1;
            //a -= Test2;
            //if(a!=null)
            //    a();//当一个委托没有指向任何方法的时候,调用的话会出现异常null

            Delegate[] delegates = a.GetInvocationList(); //遍历委托
            foreach (Delegate de in delegates)
            {
                de.DynamicInvoke();
            }

匿名函数

有另外一种使用委托的方式,不用去定义一个方法,应该说是使用匿名方法(方法没有名字)。

Func<int,int,int> plus = delegate (int a,int b){
	int temp = a+b;
	return temp;
};//格式位delegate(参数){方法体}
int res = plus(34,34);
Console.WriteLine(res);

lambda表达式

 Func<int, int, int> plus = (arg1, arg2) =>// lambda表达式的参数是不需要声明类型的
     {
         return arg1 + arg2;
     };
 Func<int, int> test2 = a => a+1;//lambda表示的参数只有一个的时候,可以不加上括号  当函数体的语句只有一句的时候,我们可以不加上大括号 也可以不加上return语句

观察者设计模式(事件)

事件(Event)是类或对象向其他类或对象通知发生的事情的一种特殊签名的委托.

public event 委托类型 事件名;

有三只动物,猫(名叫Tom),还有两只老鼠(Jerry和Jack),当猫叫的时候,触发事件(CatShout),然后两只老鼠开始逃跑(MouseRun)。

接下来用代码来实现。(设计模式-观察者模式)

 class Cat
    {
        public string name;
        public string colour;
        public event Action Run; //声明事件委托
        public Cat(string name, string colour)
        {
            this.name = name;
            this.colour = colour;
        }
        public void Coming()
        {
            Console.WriteLine(this.colour+"的猫"+this.name+"  来了");
            this.Run(); //调用事件委托
        }
    }
 class Mouse
    {
        public string name;
        public string colour;
        public Cat cat;
        public Mouse(string name, string colour,Cat cat)
        {
            this.name = name;
            this.colour = colour;
            this.cat = cat;
            cat.Run += run; //注册事件
        }

        public void run()
        {
            Console.WriteLine(colour+"的猫"+name+":说猫来了,快跑");
        }
    }

            Cat cat1 = new Cat("Tom", "蓝色");
            Mouse mouse1 = new Mouse("mouse1", "red", cat1);
            Mouse mouse2 = new Mouse("mouse2", "blue", cat1);
            Mouse mouse3 = new Mouse("mouse3", "yellow", cat1);
            cat1.Coming();//触发事件

LINQ查询语句

            //初始化武林高手
            var masterList = new List<MartialArtsMaster>()
            {
                new MartialArtsMaster() {Id = 1, Name = "黄蓉", Age = 18, Menpai = "丐帮", Kongfu = "打狗棒法", Level = 9},
                new MartialArtsMaster() {Id = 2, Name = "洪七公", Age = 70, Menpai = "丐帮", Kongfu = "打狗棒法", Level = 10},
                new MartialArtsMaster() {Id = 3, Name = "郭靖", Age = 22, Menpai = "丐帮", Kongfu = "降龙十八掌", Level = 10},
                new MartialArtsMaster() {Id = 4, Name = "任我行", Age = 50, Menpai = "明教", Kongfu = "葵花宝典", Level = 1},
                new MartialArtsMaster() {Id = 5, Name = "东方不败", Age = 35, Menpai = "明教", Kongfu = "葵花宝典", Level = 10},
                new MartialArtsMaster() {Id = 6, Name = "林平之", Age = 23, Menpai = "华山", Kongfu = "葵花宝典", Level = 7},
                new MartialArtsMaster() {Id = 7, Name = "岳不群", Age = 50, Menpai = "华山", Kongfu = "葵花宝典", Level = 8},
                new MartialArtsMaster() {Id = 8, Name = "令狐冲", Age = 23, Menpai = "华山", Kongfu = "独孤九剑", Level = 10},
                new MartialArtsMaster() {Id = 9, Name = "梅超风", Age = 23, Menpai = "桃花岛", Kongfu = "九阴真经", Level = 8},
                new MartialArtsMaster() {Id = 10, Name = "黄药师", Age = 23, Menpai = "梅花岛", Kongfu = "弹指神通", Level = 10},
                new MartialArtsMaster() {Id = 11, Name = "风清扬", Age = 23, Menpai = "华山", Kongfu = "独孤九剑", Level = 10}
            };
            //初始化武学
            var kongfuList = new List<Kongfu>()
            {
                new Kongfu() {Id = 1, Name = "打狗棒法", Power = 90},
                new Kongfu() {Id = 2, Name = "降龙十八掌", Power = 95},
                new Kongfu() {Id = 3, Name = "葵花宝典", Power = 100},
                new Kongfu() {Id = 4, Name = "独孤九剑", Power = 100},
                new Kongfu() {Id = 5, Name = "九阴真经", Power = 100},
                new Kongfu() {Id = 6, Name = "弹指神通", Power = 100}
            };
            //查询所有武学级别大于8的武林高手
            //var res = new List<MartialArtsMaster>();
            //foreach (var temp in masterList)
            //{
            //    if (temp.Level > 8)
            //    {
            //        res.Add(temp);
            //    }   
            //}

            //1,使用LINQ做查询( 表达式写法)
            //查询所有武学级别大于8的武林高手
            var res = from m in masterList //自动遍历集合中的每个对象m
                      where m.Level > 8 && m.Menpai=="丐帮"
                      select m;

            //2,扩展方法的写法
            var res1 = masterList.Where(Test);
            var res2 = masterList.Where(m=>m.Level>8); //lambda表达式写法

            //3,LINQ 联合查询
            //取得所学功夫的杀伤力大于90 的武林高手
            var res3 = from m in masterList
                       from k in kongfuList
                       where m.Kongfu == k.Name && k.Power > 90
                       select new { master = m, kongfu = k };//选择多个字段
                                                             //select m;
            //扩展方法用法
            var res4 = masterList.SelectMany(k => kongfuList, (m, k) => new { master = m, kongfu = k })
                 .Where(x => x.master.Kongfu == x.kongfu.Name && x.kongfu.Power > 90);

            //4,对查询结果做排序 orderby (descending)
            var res5 = from m in masterList
                       where m.Level > 8
                      // orderby m.Age descending//加descending就是倒序
                      orderby m.Level,m.Age //按照多个字段进行排序,如果字段的属性相同,就按照第二个属性排序
                      select m;

            //5,join on 集合联合
            var res6 = from m in masterList
                       join k in kongfuList on m.Kongfu equals k.Name
                       where k.Power > 90
                       select m;

            //6,分组查询 into groups (把武林高手按照所学功夫分类,看一下那个功夫修炼的人数最多)
            var res7 = from k in kongfuList
                       join m in masterList on k.Name equals m.Kongfu
                       into groups
                       select new { kongfu = k, count = groups.Count() };

            //7,按照自身字段分组 group
            var res8 = from m in masterList
                       group m by m.Kongfu
                       into g
                       select new { count = g.Count(), key = g.Key };//g.Key Key表示是按照那个属性分的组


            //8,量词操作符 any all 判断集合中是否满足某个条件或者全部满足
            bool res9 = masterList.Any(m => m.Menpai == "长留");
            Console.WriteLine(res);
            bool res10 = masterList.All(m => m.Menpai == "丐帮");
            Console.WriteLine(res);

            //显示信息
            foreach (var item in res8)
            {
                Console.WriteLine(item.ToString());
            }
        }

        static bool Test(MartialArtsMaster master)
        {
            if (master.Level > 8) return true;
            return false;
        }

反射和特性

1. 程序是用来处理数据的,文本和特性都是数据,而我们程序本身(类的定义和BLC中的类)这些也是数据。
2. 有关程序及其类型的数据被称为元数据(metadata),它们保存在程序的程序集中。
3. 程序在运行时,可以查看其它程序集或其本身的元数据。一个运行的程序查看本身的元数据或者其他程序集的元数据的行为叫做反射。

        Type位于System.Reflection命名空间下

        Assembly类在System.Reflection命名空间中定义,它允许访问给定程序集的元数据,它也包含了可以加载和执行程序集。

          //每一个类对应一个type对象,这个type对象存储了这个类 有哪些方法跟哪些数据 哪些成员
            MyClass my = new MyClass();//一个类中的数据 是存储在对象中的, 但是type对象只存储类的成员
            Type type = my.GetType();//通过对象获取这个对象所属类 的Type对象
            Console.WriteLine(type.Name);//获取类的名字
            Console.WriteLine(type.Namespace);//获取所在的命名空间
            Console.WriteLine(type.Assembly);//返回程序集
            FieldInfo[] array= type.GetFields();//只能获取public 字段
            foreach (FieldInfo info in array)
            {
                Console.Write(info.Name+" ");
            }
            PropertyInfo[] array2 = type.GetProperties();//获取属性
            foreach (PropertyInfo info in array2)
            {
                Console.Write(info.Name+" ");
            }
            MethodInfo[] array3 = type.GetMethods();//获取方法
            foreach (MethodInfo info in array3)
            {
                Console.Write(info.Name+" ");
            }
            //通过type对象可以获取它对应的类的所有成员(public)

            MyClass my = new MyClass();
            Assembly assem =  my.GetType().Assembly;//通过类的type对象获取它所在的程序集 Assembly
            Console.WriteLine(assem.FullName);
            Type[] types = assem.GetTypes();
            foreach (var type in types)//遍历程序集中定义的类型 	
            {
                Console.WriteLine(type);
            }
            Console.ReadKey();

特性

特性(attribute)是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。

  1.   将应用了特性的程序结构叫做目标
  2.   设计用来获取和使用元数据的程序(对象浏览器)叫做特性的消费者
  3.   NET预定了很多特性,我们也可以声明自定义特性     
  • Obsolete特性

       使用Obsolete特性将程序结构标注为过期的,并且在代码编译时,显示有用的警告信息

        [Obsolete("这个方法过时了,使用NewMethod代替")] //obsolete特性用来表示一个方法被弃用了
        static void OldMethod()
        {
            Console.WriteLine("Oldmethod");
        }

        static void NewMethod()
        {
            
        }
  • Conditional特性

Conditional特性允许我们包括或取消特定方法的所有调用。为方法声明应用Conditional特性并把编译符作为参数来使用。

#define DoTrace //如果不定义这个宏,就不会调用方法TraceMessage

class Program{
	[Conditional("DoTrace")] //其中的字符任写
	static void TraceMessage(string str){
		Console.WriteLine(str);
	}
	static void Main(){
		TraceMessage("Start of Main");
		Console.WriteLine("Doing work in Main.")
		TraceMessage("End of Main");
	}
}

还有一些特性和自定义特性,用的地方太少,等需要的时候再学习。

线程

只有一个前台线程在运行,应用程序的进程就在运行,如果多个前台线程在运行,但是Main方法结束了,应用程序的进程仍然是运行的,直到所有的前台线程完成其任务为止。

在默认情况下,用Thread类创建的线程是前台线程。线程池中的线程总是后台线程。

在用Thread类创建线程的时候,可以设置IsBackground属性,表示它是一个前台线程还是一个后台线程。

当所有的前台线程运行完毕,如果还有后台线程运行的话,所有的后台线程会被终止掉。

委托创建线程

 //一般我们会为比较耗时的操作 开启单独的线程去执行,比如下载操作
        static int Test(int i, string str)
        {
            Console.WriteLine("测试线程" + i + str);
            Thread.Sleep(100);//让当亲线程休眠(暂停线程的执行) 单位ms
            return 100;
        }
        static void Main(string[] args)
        {   //在main线程中执行 一个线程里面语句的执行 是从上到下的
        //1,通过委托 开启一个线程
            Func<int, string, int> a = Test;//赋值一个委托函数

            IAsyncResult xiancheng1 = a.BeginInvoke(100, "循环检测", null, null);// 开启一个新的线程去执行 a所引用的方法 
            //IAsyncResult 可以取得当前线程的状态
            //可以认为线程是同时执行的(异步执行)
            Console.WriteLine("main");
            while (xiancheng1.IsCompleted == false)//如果当前线程没有执行完毕
            {
                Console.Write(".");
                Thread.Sleep(10); //控制子线程的检测频率
            }
            int res1 = a.EndInvoke(xiancheng1);//取得异步线程的返回值
            Console.WriteLine(res1);


            //检测线程结束
            IAsyncResult xiancheng2 = a.BeginInvoke(100, "等待方式检测", null, null);
            bool isend = xiancheng2.AsyncWaitHandle.WaitOne(1000);// 1000毫秒表示超时时间,如果等待了1000毫秒 线程还没有结束的话 那么这个方法会返回false 
            //如果在1000毫秒以内线程结束了,那么这个方法会返回true
            if (isend)
            {
                int res2 = a.EndInvoke(xiancheng2);
                Console.WriteLine(res2);
            }


            //通过回调 检测线程结束
            //倒数第二个参数是一个委托类型的参数,表示回调函数,就是当线程结束的时候会调用这个委托指向的方法
            //倒数第一个参数用来给回调函数传递数据
            a.BeginInvoke(100, "回调检测", OnCallBack, a);
            a.BeginInvoke(100, "回调匿名检测", xiancheng3 =>
              {
                  int res4 = a.EndInvoke(xiancheng3);//匿名函数可以直接访问外部变量
                  Console.WriteLine(res4);
              }, null);
            Console.ReadKey();
         //定义的回调函数
        static void OnCallBack(IAsyncResult ar)//回调的参数固定IAsyncResult
        {
            Func<int, string, int> a = ar.AsyncState as Func<int, string, int>;//里氏转换
            int res3 = a.EndInvoke(ar);
            Console.WriteLine(res3);
        }

Thread创建线程

 static void DownloadFile(object filename)
        {
            //Thread.CurrentThread.ManagedThreadId获取当前线程的ID
            Console.WriteLine("开始下载:" + Thread.CurrentThread.ManagedThreadId + filename);
            Thread.Sleep(2000);
            Console.WriteLine("下载完成");

        }
        static void Main(string[] args)
        {
            Thread t = new Thread(DownloadFile);
            t.IsBackground = true;//设置为后台线程 
            t.Start("xxx");

            Console.WriteLine("主线程");
            t.Join(); //当前线程睡眠,等待t线程执行完,然后继续运行下面的代码
            Console.ReadKey();

            MyThread my = new MyThread("xxx.bt","http://www.xxx.bbs");
            Thread t1 = new Thread(my.DownFile);//我们构造一个thread对象的时候,可以传递一个静态方法,也可以传递一个对象的普通方法
            t1.Start();
            t1.Abort();//终止这个线程的执行
        }

线程池

  //开启一个工作线程,参数一为函数,后面的参数是传入函数的参数
  ThreadPool.QueueUserWorkItem(DownloadFile,"xxx");

任务

 Task t = new Task(DownloadFile,"xxx");//创建任务
 t.Start();

 TaskFactory tf = new TaskFactory(); //创建任务工厂
 Task t1 = tf.StartNew(DownloadFile,"xxxx");

连续任务

        static void DoFirst()
        {
            Console.WriteLine("do  in task : " + Task.CurrentId);
            Thread.Sleep(3000);
        }
        static void DoSecond(Task t)
        {
            Console.WriteLine("task " + t.Id + " finished.");
            Console.WriteLine("this task id is " + Task.CurrentId);
            Thread.Sleep(3000);
        }
            Task t1 = new Task(DoFirst);
            Task t2 = t1.ContinueWith(DoSecond);
            Task t3 = t1.ContinueWith(DoSecond);
            Task t4 = t2.ContinueWith(DoSecond);
            t1.Start();

任务层次结构

我们在一个任务中启动一个新的任务,相当于新的任务是当前任务的子任务,两个任务异步执行,如果父任务执行完了但是子任务没有执行完,它的状态会设置为WaitingForChildrenToComplete,只有子任务也执行完了,父任务的状态就变成RunToCompletion

        static void ParentTask()
        {
            Console.WriteLine("task id " + Task.CurrentId);
            var child = new Task(ChildTask);
            child.Start();
            Thread.Sleep(1000);
            Console.WriteLine("parent started child , parent end");
        }
        static void ChildTask()
        {
            Console.WriteLine("child");
            Thread.Sleep(5000);
            Console.WriteLine("child finished ");
        }
             var parent = new Task(ParentTask);
            parent.Start();
            Thread.Sleep(2000);
            Console.WriteLine(parent.Status);
            Thread.Sleep(4000);
            Console.WriteLine(parent.Status);
            Console.ReadKey();

锁是用来锁住对象的,被锁住的对象只有在当前线程解开后,才能被其他线程访问该对象

static void RaceCondition(object o ){
	StateObject state = o as StateObject;
	int i = 0;
	while(true){
		lock(state){ //锁住state对象
			state.ChangeState(i++);			
		}

	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猪猪派对

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值