首页 > 编程语言 >C#高级编程1

C#高级编程1

时间:2023-01-09 19:35:36浏览次数:41  
标签:name C# void 编程 高级 线程 抽象类 public string

C#高级编程1

 

 

 

 

 

 

 

 

 

 

 

 

抽象类 和接口

抽象类

抽象类是包含抽象方法的类;

抽象方法只有方法声明,没有方法体;

抽象类和抽象方法用关键字abstract标识;

抽象类不能实例化,对抽象类的实例化是非法的;

但是可以声明抽象类的引用,指向实现该抽象类的子类对象;

抽象类不能使用sealed关键字,sealed和abstract在概念上是相反的;

抽象类的子类中必须实现全部抽象方法,否则子类也要声明为抽象类;

实现了抽象类方法的子类,称为抽象类的具体类、或者实现类;

定义抽象方法是为了让不同的子类对抽象方法有不同的实现;

抽象类不能多继承;

 

接口

接口是一个特殊的类,用于定义子类需要遵循的规则;

接口使用interface进行声明;

接口中不能有字段,因为字段必须分配内存空间,而接口无法实例化;

接口中可以定义属性、方法、索引器;

接口中所有属性默认具有public和abstract属性;

接口的实现类中,必须对所有的成员进行实现;

接口可以多继承,子类必须实现所有接口中的所有成员;

 

 

 

抽象类和接口对比

异同

抽象类

接口

成员

可以有字段成员;

方法、属性成员;

不能有字段成员;(报错:接口不能包含实例字段)

只能有方法和属性成员;

实例化对象

声明引用

多继承

访问权限

默认public;

可以public;

可以protected;

不能private;

默认public;

可以public;

可以protected;

不能private;(错误:虚拟成员或抽象成员不能是私有的)

abstract

要显示声明abstract;

有abstract成员;

也可以有非abstract成员;

所有成员默认abstract属性;

也可以显示声明;

所有成员都是abstract;

override

实现抽象成员不需override;

实现抽象成员不需override;

多级继承

抽象类可以继承自其他抽象类;

接口可以继承自其他接口,并且可以多继承;

示例

    /// <summary>

    /// 会飞的接口

    /// </summary>

    interface IFlyable

    {

        string Name { get; }

        void Fly();

}

 

    /// <summary>

    /// 鸟类,实现会飞的接口

    /// </summary>

    class Bird : IFlyable

    {

        private string _name;

        public string Name { get =>_name; }

        public Bird(string name)

        {

            _name = name;

        }

        public void Fly()

        {

            Console.WriteLine($"我是一只鸟,我的名字叫 {Name},我会飞");

        }

    }

/// <summary>

   /// 飞机类,实现会飞的接口

   /// </summary>

    class Plane : IFlyable

    {

        private string _name;

        public string Name { get => _name;  }

        public Plane(string name)

        {

            _name = name;

        }

        public void Fly()

        {

            Console.WriteLine($"我是一架飞机,我的名字叫 {Name},我会飞");

        }

    }

  static void Main(string[] args)

        {

            Bird bird = new Bird("山鸡");

            Plane plane = new Plane("C919");

            bird.Fly();

            plane.Fly();

        }

输出

我是一只鸟,我的名字叫 山鸡,我会飞

我是一架飞机,我的名字叫 C919,我会飞

 class Person

    {

        private string _name;

        private float _height;

        private float _weight;

        /// <summary>

        /// 构造函数

        /// </summary>

        /// <param name="name">姓名</param>

        /// <param name="height">身高(米)</param>

        /// <param name="weight">体重(公斤)</param>

        public Person(string name,float height, float weight)

        {

            _name = name;

            _height = height;

            _weight = weight;

        }

        /// <summary>

        /// 身高(米)

        /// </summary>

        public float Height { get => _height; set => _height = value; }

        /// <summary>

        /// 体重(公斤)

        /// </summary>

        public float Weight { get => _weight; set => _weight = value; }

        /// <summary>

        /// 姓名

        /// </summary>

        public string Name { get => _name; set => _name = value; }

 

        //计算肥胖的公式有多个,先是体重指数,用体重(kg)/身高(m)^2 ,正常范围是18.5-22.9,大于等于24为超重,大于等于28为肥胖

        /// <summary>

        /// 是否过于肥胖

        /// </summary>

        public void BMI()

        {

            float bmi = _weight / (_height * _height);

            if (bmi > 28) Console.WriteLine($"尊敬的 {_name},您属于肥胖类型");

            else Console.WriteLine($"尊敬的 {_name},您不属于肥胖类型");

        }

 

 

}

  static void Main(string[] args)

        {

 

            //位置参数:按照参数顺序定位参数

            Person zhuwuneng = new Person("猪悟能", 100f, 1.8f);

            zhuwuneng.BMI();

 

            //命名参数:按照参数名称定位参数,与位置无关

            Person zhubajie = new Person(name: "猪八戒" ,weight: 100f, height: 1.8f);

            zhubajie.BMI();

        }

输出:

尊敬的 猪悟能,您不属于肥胖类型

尊敬的 猪八戒,您属于肥胖类型

 

委托、Lambda表达式

委托

当需要将方法作为参数传递给另一个方法时,就要使用委托;

C#不允许直接传递方法,而是把方法封装到对象中,这个对象就是委托;

委托是一种特殊的对象,其中包含一个或多个函数的地址;

委托本质是一个类,要先创建类,然后实例化类的对象,才可以使用它;

继承关系:自定义委托类delegate→System.MulticastDelegate→System.Delegate

delegate int CalInvoker(int);//定义一个委托类

CalInvoker calInvoker;实例化委托类的对象

 

Action<T>表示返回类型为void的函数,参数最多16个;

Func<T>表示有返回值的函数,入参最多16个,返回值1个;

Action<in T1,in T2> Func<in T1,out TResult>

 

 

lambda

使用场景:把lambda表达式赋值给委托类型;只要使用委托形参的地方,都可以传入lambda表达式作为实参;

lambda运算符=>左侧是所需参数(方法形参),右边是实现代码(方法体);

参数类型推断:lambda表达式参数的类型根据定义的委托类型进行推断;

只有一行代码的lambda表达式,可以不使用花括号{},可以不使用return;(编译器自动添加return)

多行代码的lambda表达式,必须使用花括号{}和return关键字;

闭包:通过lambda表达式访问外部变量,这叫做闭包;

lambda表达式可以修改闭包(外部变量)的值,并且修改的值可以被外部访问;

lambda表达式的内部实现:

x=>x+val;

public class AnonymousClass

{

private int val;

public AnonymousClass(int val){this.val=val;}

public int AnonymousMethod(int x){return x+val;}

}

labmda表达式可以用于任何类型为委托的地方;

类型为Expression或者Expression<T>时,可以使用lambda,编译器会生成一个表达式树;

事件

事件使用2个参数的方法:第一个参数是一个对象,是事件的发送者;第二个参数提供了事件相关信息,第二个参数随不同的事件类型而改变;

EventHandler<TEventArgs>第一个参数必须是object类型,第二个参数是T类型,必须派生自EventArgs;

public event EventHandler<CarInfoEventArgs> NewCarInfo;

public delegate void EventHandler<TEventArgs>(object sender,TEventArgs e) where TEventArgs:EventArgs

private EventHandler<CarInfoEventArgs> _newCarInfo;

public event EventHandler<CarInfoEventArgs> NewCarInfo

{add=>_newCarInfo+=value;remove=>_newCarInfo-=value;}

触发事件

EventHandler<CarInfoEventArgs> newCarInfo=NewCarInfo;

if(newCarInfo!=null){newCarInfo(this,new CarInfoEventArgs(car));}

protected virtual void RaiseNewCarInfo(string car)

{NewCarInfo?.Invoke(this,new CarInfoEventArgs(car))}

事件测试

using System;

 

namespace ConsoleCore0104

{

    //事件参数类

    public class CarInfoEventArgs : EventArgs

    {

        public string Car { get; }

        public CarInfoEventArgs(string car) => Car = car;

      

    }

    //汽车经销商

    public class CarDealer

    {

        //新车到店的事件容器,用于存放新车到店后的回调函数(事件处理函数)

        //EventHandler<TEventArgs>是一个泛型委托,指定参数类型就可以定义这个委托

        //EventHandler<TEventArgs>第一个参数必须是object类型,第二个参数是T类型,必须派生自EventArgs;

        public event EventHandler<CarInfoEventArgs> NewCarInfo;

        public void NewCar(string car)

        {

            Console.WriteLine($"经销商:新车已到店 {car}");

            //如果事件容器不为空,则调用执行其中的所有函数(顺序不定)

            //事件触发者是汽车经销商,所以sender就是this

            //?表示如果NewCarInfo不是null,就执行Invoke函数;如果为null,不执行Invoke函数;

            NewCarInfo?.Invoke(this,new CarInfoEventArgs(car));

            Console.WriteLine();

        }

    }

    //消费者

    public class Consumer

    {

        private string _name;

        public Consumer(string name) => _name = name;

        //新车到店后的回调函数

        //用+=将客户的回调函数添加到事件容器中

        //用-=取消订阅(新车到店后不会再执行该函数)

        //如果客户订阅了新车到店事件,新车到店后就会执行该函数

        public void NewCarIsHere(object sender, CarInfoEventArgs e)

        {

            Console.WriteLine($"尊敬的客户:{_name},新车已到店 {e.Car}");

        }

    }

    //Main

    class Program

    {

 

        static void Main(string[] args)

        {

            var dealer = new CarDealer();//实例化经销商

            var ZhaoBenShan = new Consumer("赵本山");//实例化消费者--赵本山

            dealer.NewCarInfo += ZhaoBenShan.NewCarIsHere;//赵本山--订阅新车到店

            dealer.NewCar("比亚迪 唐");//经销商新车到店事件--比亚迪唐

            var LiuNeng = new Consumer("刘能");//实例化消费者--刘能

            dealer.NewCarInfo += LiuNeng.NewCarIsHere;//刘能--订阅新车到店

            dealer.NewCar("长安UNIT");//经销商新车到店事件--长安UNIT

            dealer.NewCarInfo -= ZhaoBenShan.NewCarIsHere;//赵本山--取消订阅新车到店

            dealer.NewCar("众泰保时捷");//经销商新车到店事件--众泰保时捷

        }

    }

}

输出结果:

经销商:新车已到店 比亚迪 唐

尊敬的客户:赵本山,新车已到店 比亚迪 唐

 

经销商:新车已到店 长安UNIT

尊敬的客户:赵本山,新车已到店 长安UNIT

尊敬的客户:刘能,新车已到店 长安UNIT

 

经销商:新车已到店 众泰保时捷

尊敬的客户:刘能,新车已到店 众泰保时捷

 

总结

发布者:谁创建了委托(事件),谁就是发布者;

发布者:发布者负责委托内函数(函数的容器、函数指针的容器)的调用;

订阅者:谁向委托添加函数,谁就是订阅者;

订阅者:订阅者负责定义函数,并将函数添加到委托中(函数的容器中);

订阅者:订阅者定义的函数类型必须和发布者的委托类型匹配;

  public void ParallelTest()
        {
            sb.Clear();
            var cts = new CancellationTokenSource();
            cts.Token.Register(() => sb.Append("\n任务已取消\n"));
            new Task(() => { Thread.Sleep(500); cts.Cancel(); }).Start();
            try
            {
                ParallelLoopResult res = Parallel.For(0, 100,
                    new ParallelOptions() { CancellationToken = cts.Token, },
                    x => { 
                        sb.Append($"\n循环已开始,序号={x}\n");
                        int sum = 0;
                        for (int i = 0; i < 100; i++)
                        {
                            Thread.Sleep(2);
                            sum += i;
                        }
                        sb.Append($"\n循环已结束,序号={x}\n");
                    }
                    ); 
            }
            catch (Exception ex)
            {

                sb.Append("\n"+ex.Message+"\n");
            }
            richTextBox1.Text = sb.ToString();
        }

 

 

 public void ThreadTest2()
        {
            sb.Clear();
            for (int i = 0; i < 5; i++)
            {
                System.Threading.ThreadPool.QueueUserWorkItem(JobForThread);
            }

            richTextBox1.Text = sb.ToString();
        
        }
        StringBuilder sb = new StringBuilder();
        public void JobForThread(object state)
        {
            for (int i = 0; i < 3; i++)
            {
                sb.Append( $"这是第 {i} 个任务,运行的线程ID是 {System.Threading.Thread.CurrentThread.ManagedThreadId}\n");
            }
            System.Threading.Thread.Sleep(50);
        }

  public void ThreadTest()
        {
            int workThreadCount, completionPortThreadCount;
            richTextBox1.Text += "\n默认值:\n";
            System.Threading.ThreadPool.GetMaxThreads(out workThreadCount, out completionPortThreadCount);
            richTextBox1.Text += "\n线程池中最大工作线程数=" + workThreadCount + "\n线程池中最大IO线程数=" + completionPortThreadCount;
            // 线程池中最大工作线程数 = 2047
            //线程池中最大IO线程数 = 1000
            System.Threading.ThreadPool.GetMinThreads(out workThreadCount, out completionPortThreadCount);
            richTextBox1.Text += "\n线程池中最小工作线程数=" + workThreadCount + "\n线程池中最小IO线程数=" + completionPortThreadCount;
            richTextBox1.Text += "\n\n自定义值:\n";
            System.Threading.ThreadPool.SetMaxThreads(100,200);
            System.Threading.ThreadPool.SetMinThreads(1,2);
            System.Threading.ThreadPool.GetMaxThreads(out workThreadCount, out completionPortThreadCount);
            richTextBox1.Text += "\n线程池中最大工作线程数=" + workThreadCount + "\n线程池中最大IO线程数=" + completionPortThreadCount;
            System.Threading.ThreadPool.GetMinThreads(out workThreadCount, out completionPortThreadCount);
            richTextBox1.Text += "\n线程池中最小工作线程数=" + workThreadCount + "\n线程池中最小IO线程数=" + completionPortThreadCount;

        }

默认值:

线程池中最大工作线程数=2047
线程池中最大IO线程数=1000
线程池中最小工作线程数=8
线程池中最小IO线程数=8

自定义值:

线程池中最大工作线程数=100
线程池中最大IO线程数=200
线程池中最小工作线程数=1
线程池中最小IO线程数=2

            t.GetMembers();//获取所有成员
            t.GetMethods();//获取所有方法
            t.GetFields();//获取所有字段
            t.GetProperties();//获取所有属性(get set封装的字段)
            t.GetConstructors();//获取所有构造函数
            t.GetDefaultMembers();//获取所有默认成员

通过type获取类的所有成员名称

public void TypeTest()
        {
            var t = typeof(Form);
            var mems = t.GetProperties();
            StringBuilder sb = new StringBuilder();
            sb.Append(t.Name + "\n");
            sb.Append(t.FullName + "\n");
            sb.Append(t.Namespace + "\n");

            sb.Append("\n");
            foreach (var item in mems)
            {
                sb.Append(item.Name + "\n");
            }
            richTextBox1.Text = (sb.ToString());
        }

类型

Thread

Thread 需要自己调度,适合长跑型的操作。

ThreadPool

ThreadPool是Thread基础上封装的一个线程池,目的是减少频繁创建线程的开销。

ThreadPool适合频繁、短期执行的小操作。

但是ThreadPool不能突然中断线程的执行,在多核时代,它的效率也不尽如人意。

Task

Task或者说TPL(task parallel library)是一个更上层的封装,NB之处在于continuation。

能用Task就用Task,底下都是用的Thread或者ThreadPool。

Timer

另外还有个特别的是Timer,所有Timer实例都是在一个专门的Timer线程上调度的。所以不要写的很重,要不然原本已经很低的精度会更加惨不忍睹。

分类

前台

后台

前台线程:主程序必须等待线程执行完毕后才能退出程序,Thread默认为前台程序,可以设置为后台程序;

后台线程:主程序执行完毕后就退出,不管线程是否完成,Thread Pool默认是后台程序

工作

I/O

工作者线程:workerThreads是主要用作管理CLR内部对象的运作,通常用于计算密集的任务。在任务执行的过程中,需要CPU不间断地处理,所以,在工作者线程的执行过程中,CPU和线程的资源是充分利用的;

I/O线程:completionPortThreads线程主要用来完成输入和输出的工作的,在这种情况下, 计算机需要I/O设备完成输入和输出的任务,在处理过程中,CPU是不需要参与处理过程的,此时正在运行的线程将处于等待状态,只有等任务完成后才会有事可做, 这样就造成线程资源浪费的问题,可以通过线程池来解决这样的问题。

标签:name,C#,void,编程,高级,线程,抽象类,public,string
From: https://www.cnblogs.com/zhangdezhang/p/17012863.html

相关文章