C# 高级编程1

  • LINQ to Objects

  • LINQ to XML

ADO.NET是.NET Framework中的一个模块,一个重要组件,用于建立应用程序和数据源之间的连接。

抽象类 和接口

抽象类

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

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

抽象类和抽象方法用关键字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是不需要参与处理过程的,此时正在运行的线程将处于等待状态,只有等任务完成后才会有事可做, 这样就造成线程资源浪费的问题,可以通过线程池来解决这样的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值