【C# Programming】委托和lambda表达式、事件

目录

一、委托和lambda表达式

1.1 委托概述

1.2 委托类型的声明

1.3 委托的实例化

1.4 委托的内部机制 

1.5 Lambda 表达式

1.6 语句lambda

1.7 表达式lambda

1.8 Lambda表达式

1.9 通用的委托

1.10 委托没有结构相等性

1.11 Lambda表达式和匿名方法的内部机制

1.12 外部变量

1.13 外部变量的CIL实现

二、事件

2.1 多播委托

2.2 使用多播委托来编码Observer模式

2.3 委托操作符

2.4 错误处理

2.5 事件的作用

2.6 事件的声明

2.7 编码规范

2.8 事件的内部机制

2.9 自定义事件的实现


一、委托和lambda表达式

1.1 委托概述

        C/C++ 利用”函数指针”将方法的引用作为实参传给另一个方法。 C# 利用委托提供相同的功能。委托允许捕获对方法的引用,并像传递其他对象那样传递这个引用,像调用其他方法那样调用这个被捕获的方法。 例如:

public static void BubbleSort(int[] items, ComparisonHandler comparisonMethod)
{int i, j, temp;if(comparisonMethod == null)throw new ArgumentNullException("comparisonMethod");if(items == null)return;for(i = items.Length - 1; i >= 0; i--){for(j = 1; j <= i; j++){if(comparisonMethod(items[j - 1], items[j])){temp = items[j - 1];items[j - 1] = items[j];items[j] = temp;}}}
}

1.2 委托类型的声明

        为了声明委托,要使用delegate 关键字,后面跟着方法的签名。这个方法的签名是委托所引用的方法的签名。 例如:

public delegate bool ComparisonHandler(int first, int second);

        委托可以嵌套在类中。 假如委托声明出现在另一个类的内部,则委托类型就会成为嵌套类型。

class DelegateSample
{public delegate bool ComparisonHandler(int first, int second);
}

1.3 委托的实例化

        为了实例化委托,需要一个和委托类型自身签名匹配的方法。 例如:

public delegate bool ComparisonHandler(int first, int second);
class DelegateSample
{public static void BubbleSort(int[] items, ComparisonHandler comparisonMethod){//…}public static bool GreaterThan(int first, int second){return first > second;}static void Main(){int i;int[] items = new int[5];for(i = 0; i < items.Length; i++){Console.Write("Enter an integer: ");items[i] = int.Parse(Console.ReadLine());}BubbleSort(items, GreaterThan);for(i = 0; i < items.Length; i++)Console.WriteLine(items[i]);}
}

1.4 委托的内部机制 

        委托是特殊的类,.Net 中的委托类型总是派生自System.MulticastDelegate, 后者又从 System.Delegate 派生。

        C# 编译器不允许声明直接或间接从System.Delegate 或者System.MulicastDelegate 派生的类。

1.5 Lambda 表达式

        C#2.0 引入非常精简的语法创建委托,相关的特性被称为匿名方法。 C# 3.0 相关的特性称为Lambda 表达式。这两种语法统称 匿名函数。Lambda   表达式本身分为两种类型: 语句lambda和表达式 lambda。

1.6 语句lambda

        语句lambda 由形参列表,后面跟lambda 操作符=>, 然后跟一个代码块构成。 例如: 

public class DelegateSample
{//…..public static void Main(){int i;int[] items = new int[5];for(i = 0; i < items.Length; i++){Console.Write("Enter an integer: ");items[i] = int.Parse(Console.ReadLine());}BubbleSort(items, (int first, int second) => { return first < second;});for(i = 0; i < items.Length; i++){Console.WriteLine(items[i]);}}
}

        当编译器能从Lambda表达式转换成的委托推断出类型,所有Lambda都不需要显式声明参数类型。 在不能推断出类型时,C#要求显式指定Lambda类型。只要显式指定了一个Lambda参数类型,所有参数类型都必须被显式指定, 例如:

public static void ChapterMain()
{int i;int[] items = new int[5];for(i = 0; i < items.Length; i++){Console.Write("Enter an integer:");items[i] = int.Parse(Console.ReadLine());}DelegateSample.BubbleSort(items, (first, second) => { return first < second;});for(i = 0; i < items.Length; i++){Console.WriteLine(items[i]);}
}

        当只有单个参数,而且类型可以推断时,这种Lambda 表达式可省略围绕参数列表的圆括号。如果Lambda没有参数, 或者有不止一个参数,或者显式指定了类型的单个参数,那么就必须将参数列表放到圆括号中。  例如:

public class Program
{public static void ChapterMain(){IEnumerable<Process> processes = Process.GetProcesses().Where(process => { return process.WorkingSet64 > 1000000000; });}
}

        无参数的语句Lambda

public static void ChapterMain()
{Func<string> getUserInput = () =>{string input;do{input = Console.ReadLine();}while(input.Trim().Length == 0);return input;};
}

1.7 表达式lambda

        表达式lambda只有要返回的表达式,完全没有语句块。例如:

public static void Main()
{int i;int[] items = new int[5];for(i = 0; i < items.Length; i++){Console.Write("Enter an integer:");items[i] = int.Parse(Console.ReadLine());}DelegateSample.BubbleSort(items, (first, second) => first < second);for(i = 0; i < items.Length; i++){Console.WriteLine(items[i]);}
}

        和null字面量相似,匿名函数不与任何类型关联。它的类型由它将要转换成的类型决定。所以不能对一个匿名方法使用typeof()操作符。另外,只有将匿名方法转换成一个特定类型后才能调用GetType

1.8 Lambda表达式

1.9 通用的委托

        .Net 3.5 包含了一组通用的委托。System.Func 系列委托代表有返回值方法,而System.Action 系列委托代表返回void 的方法。Func 委托的最后一个参数总是委托的返回类型,其他参数依次对应于委托参数的类型。

//public delegate void Action();
//public delegate void Action<in T>(T arg);
//public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
//public delegate void Action<in T1, in T2, in T3>(T1 arg1, T2 arg2, T3 arg3);
//public delegate void Action<in T1, in T2, in T3, in T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
// ...
//public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>(
//        T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, 
//         T13 arg13, T14 arg14, T15 arg15, T16 arg16);//public delegate TResult Func<out TResult>();
//public delegate TResult Func<in T, out TResult>(T arg);
//public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
//public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3);
//public delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
// ...
//public delegate TResult Func<   in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16,
//       out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12,
//        T13 arg13, T14 arg14, T15 arg15, T16 arg16);             

        在许多情况下,.NET 3.5 添加的Func 委托能完全避免定义自己的委托类型。例如:

public static void BubbleSort(int[] items, Func<int, int, bool> comparisonMethod)

1.10 委托没有结构相等性

         .NET 委托类型不具备结构相等性。也就是说,不能将某个委托类型的对象转换成不相关的委托类型,即使这两个委托类型的形参和返回类型完全一致。 然而,通过C# 4.0 添加的对可变性的支持,可以在某些引用类型之间进行引用转换。

public static void ChapterMain()
{// ContravarianceAction<object> broadAction =(object data) =>{Console.WriteLine(data);};Action<string> narrowAction = broadAction;// CovarianceFunc<string> narrowFunction =() => Console.ReadLine();Func<object> broadFunction = narrowFunction;// Contravariance and covariance combinedFunc<object, string> func1 =(object data) => data.ToString();Func<string, object> func2 = func1;
}

1.11 Lambda表达式和匿名方法的内部机制

        当编译器遇到匿名方法时, 会把它转换为特殊的隐藏的类,字段和方法。 例如:

public static void Main()
{int i;int[] items = new int[5];for(i = 0; i < items.Length; i++){Console.Write("Enter an integer:");items[i] = int.Parse(Console.ReadLine());}BubbleSort(items, DelegateSample.__AnonymousMethod_00000000);for(i = 0; i < items.Length; i++){Console.WriteLine(items[i]);}
}
private static bool __AnonymousMethod_00000000(int first, int second)
{return first < second;
}

1.12 外部变量

        在Lambda表达式外部声明的局部变量称为表达式的外部变量。当Lambda主体使用一个外部变量时, 就说该变量被这个lambda捕获

public static void ChapterMain()
{int i;int[] items = new int[5];int comparisonCount = 0;for(i = 0; i < items.Length; i++){Console.Write("Enter an integer:");items[i] = int.Parse(Console.ReadLine());}DelegateSample.BubbleSort(items, (int first, int second) => {comparisonCount++; return first < second; });for(i = 0; i < items.Length; i++)Console.WriteLine(items[i]);Console.WriteLine("Items were compared {0} times.", comparisonCount);
}

        如果Lambda表达式捕获了外部变量,根据该表达式创建委托可能具有比局部变量更长的生存期。在此情况下,被捕获的变量的生存期变长了。

1.13 外部变量的CIL实现

        在Lambda表达式外部声明的局部变量称为表达式的外部变量。当Lambda主体使用一个外部变量时, 就说该变量被这个lambda捕获

private sealed class __LocalsDisplayClass_00000001
{public int comparisonCount;public bool __AnonymousMethod_00000000(int first, int second){comparisonCount++;return first < second;}
}
public static void Main()
{int i;__LocalsDisplayClass_00000001 locals = new __LocalsDisplayClass_00000001();locals.comparisonCount = 0;int[] items = new int[5];for(i = 0; i < items.Length; i++){Console.Write("Enter an integer:");items[i] = int.Parse(Console.ReadLine());}DelegateSample.BubbleSort(items, locals.__AnonymousMethod_00000000);for(i = 0; i < items.Length; i++)Console.WriteLine(items[i]);Console.WriteLine("Items were compared {0} times.", locals.comparisonCount);
}

二、事件

2.1 多播委托

        委托本身是发布-订阅模式的基本单位

        一个委托值可以引用一系列方法的, 这些方法将顺序调用。这样的委托称为多播委托。利用多播委托,单一事件的通知可以发布给多个订阅者

2.2 使用多播委托来编码Observer模式

        定义订阅者方法

class Cooler
{public Cooler(float temperature) {Temperature = temperature;}public float Temperature { get; set; }public void OnTemperatureChanged(float newTemperature){if(newTemperature > Temperature)System.Console.WriteLine("Cooler: On");elseSystem.Console.WriteLine("Cooler: Off");}
}
class Heater
{public Heater(float temperature) {Temperature = temperature;}public float Temperature { get; set; }public void OnTemperatureChanged(float newTemperature){if(newTemperature < Temperature)System.Console.WriteLine("Heater: On");elseSystem.Console.WriteLine("Heater: Off");}
}

        定义发布者

public class Thermostat
{public Action<float> OnTemperatureChange { get; set; }public float CurrentTemperature{get { return _CurrentTemperature; }set{if(value != CurrentTemperature){_CurrentTemperature = value;}}}private float _CurrentTemperature;
}

        连接发布者和订阅者

public static void Main()     
{        Thermostat thermostat = new Thermostat();            Heater heater = new Heater(60);Cooler cooler = new Cooler(80);            string temperature;            // Using C# 2.0 or later syntax.          thermostat.OnTemperatureChange +=                heater.OnTemperatureChanged;       thermostat.OnTemperatureChange +=                cooler.OnTemperatureChanged;       Console.Write("Enter temperature: ");           temperature = Console.ReadLine();          thermostat.CurrentTemperature = int.Parse(temperature);     
}

        调用委托

public class Thermostat
{// Define the event publisherpublic Action<float> OnTemperatureChange { get; set; }public float CurrentTemperature{get { return _CurrentTemperature; }set{if(value != CurrentTemperature){_CurrentTemperature = value;// INCOMPLETE:  Check for null needed Call subscribersOnTemperatureChange(value);}}}private float _CurrentTemperature;
}

        检查null值

public static void ChapterMain()
{Thermostat thermostat = new Thermostat();Heater heater = new Heater(60);Cooler cooler = new Cooler(80);Action<float> delegate1;Action<float> delegate2;Action<float> delegate3;// use Constructor syntax for C# 1.0.delegate1 = heater.OnTemperatureChanged;delegate2 = cooler.OnTemperatureChanged;Console.WriteLine("Invoke both delegates:");delegate3 = delegate1;delegate3 += delegate2;delegate3(90);Console.WriteLine("Invoke only delegate2");delegate3 -= delegate1;delegate3(30);
}

2.3 委托操作符

        为了合并多个订阅者,要使用+= 操作符。这个操作符会获取第一个委托,并将第二个委托添加到委托链中。 要从委托链中删除委托,则要使用-=操作符

public static void ChapterMain()
{Thermostat thermostat = new Thermostat();Heater heater = new Heater(60);Cooler cooler = new Cooler(80);Action<float> delegate1;Action<float> delegate2;Action<float> delegate3;// use Constructor syntax for C# 1.0.delegate1 = heater.OnTemperatureChanged;delegate2 = cooler.OnTemperatureChanged;Console.WriteLine("Invoke both delegates:");delegate3 = delegate1;delegate3 += delegate2;delegate3(90);Console.WriteLine("Invoke only delegate2");delegate3 -= delegate1;delegate3(30);
}

        我们还可以使用+ 和- 合并委托

public static void ChapterMain()
{Thermostat thermostat = new Thermostat();Heater heater = new Heater(60);Cooler cooler = new Cooler(80);Action<float> delegate1, delegate2, delegate3;delegate1 = heater.OnTemperatureChanged;delegate2 = cooler.OnTemperatureChanged;Console.WriteLine("Combine delegates using + operator:");delegate3 = delegate1 + delegate2;delegate3(60);Console.WriteLine("Uncombine delegates using - operator:");delegate3 = delegate3 - delegate2;delegate3(60);
}

        无论+ - 还是+= 、-=,在内部都是使用静态方法system.Delegate.combine() 和System.Delegate.Remove()来实现的。Combine 会连接两个参数,将两个委托的调用列表按顺序连接起来,Remove 则将第二个参数指定的委托删除

        顺序调用

2.4 错误处理

        假如一个订阅者发生了异常,链中后续的订阅者就收不到通知

public static void Main()
{Thermostat thermostat = new Thermostat();Heater heater = new Heater(60);Cooler cooler = new Cooler(80);string temperature;thermostat.OnTemperatureChange +=heater.OnTemperatureChanged;thermostat.OnTemperatureChange +=(newTemperature) =>{throw new InvalidOperationException();};thermostat.OnTemperatureChange +=cooler.OnTemperatureChanged;Console.Write("Enter temperature: ");temperature = Console.ReadLine();thermostat.CurrentTemperature = int.Parse(temperature);
}

        为了避免该问题,必须手动遍历委托链并单独调用委托

public class Thermostat {public Action<float> OnTemperatureChange;public float CurrentTemperature{get { return _CurrentTemperature; }set{if(value != CurrentTemperature) {_CurrentTemperature = value;Action<float> onTemperatureChange = OnTemperatureChange;if (onTemperatureChange != null) {List<Exception> exceptionCollection =   new List<Exception>();foreach(Action<float> handler in onTemperatureChange.GetInvocationList()){try  {handler(value);}catch(Exception exception)   {exceptionCollection.Add(exception);}}if(exceptionCollection.Count > 0) throw new AggregateException(  "There were exceptions thrown by " +  "OnTemperatureChange Event subscribers.", exceptionCollection);}}}}private float _CurrentTemperature;
}

2.5 事件的作用

        封装订阅: 事件仅对包容类内部对象提供对赋值操作符的支持。

public static void Main()
{Thermostat thermostat = new Thermostat();Heater heater = new Heater(60);Cooler cooler = new Cooler(80);string temperature;thermostat.OnTemperatureChange = heater.OnTemperatureChanged;// Bug: Assignment operator overrides // previous assignment.thermostat.OnTemperatureChange =    cooler.OnTemperatureChanged;Console.Write("Enter temperature: ");temperature = Console.ReadLine();thermostat.CurrentTemperature = int.Parse(temperature);
}

        封装发布: 事件确保只有包容类才能触发异常

public static void ChapterMain()
{//……..thermostat.OnTemperatureChange +=  heater.OnTemperatureChanged;thermostat.OnTemperatureChange +=cooler.OnTemperatureChanged;// Bug: Should not be allowedthermostat.OnTemperatureChange(42);
}

2.6 事件的声明

        C# 使用事件解决了委托的两大问题。Event 定义了一个新的成员类型,例如:

public class Thermostat 
{public class TemperatureArgs : System.EventArgs {public TemperatureArgs(float newTemperature){NewTemperature = newTemperature;}public float NewTemperature { get; set; }}// Define the event publisherpublic event EventHandler<TemperatureArgs> OnTemperatureChange = delegate { };public float CurrentTemperature{get { return _CurrentTemperature; }set { _CurrentTemperature = value; }}private float _CurrentTemperature;
}

         添加关键字event后,会禁止为一个public 委托字段使用赋值操作符,只有包容类才能调用向所有委托发出的通知委托; delegate{}表示一个空委托,代表由零个侦听者构成的集合。通过赋值空委托,可以引发事件而不必检查是否有侦听者

2.7 编码规范

        为了获得所需功能,需要将原始委托变量声明为字段,然后添加event关键字。为了遵循C#编码规范,需要将原始委托替换成新的委托类型 EventHandle,例如:

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e)where TEventArgs : EventArgs;
  • 第一参数sender是object 类型, 它包含对调用委托的那个对象的一个引用(静态事件为null)  
  • 第二参数是System.EventArgs类型的,或者从System.EventArgs派生,但包含了事件的附加数据。

        触发事件通知

public float CurrentTemperature
{get { return _CurrentTemperature; }set {if(value != CurrentTemperature){_CurrentTemperature = value;// If there are any subscribers, notify them of changes in temperature by invoking said subcribersOnTemperatureChange?.Invoke( this, new TemperatureArgs(value));}}
}

规范 :

  • 要在调用委托前检查它的值不为null  
  • 不要为非静态事件的sender传递null 值  
  • 要为静态事件的sender传递null值
  • 不要为eventArgs传递null值 要为事件使用EventHandler<TEventArgs> 委托类型
  • 要为TEventArgs 使用System.EventArgs类型或者它的派生类型  
  • 考虑使用System.EventArgs的子类作为事件的实参类型,除非完全确定事件永远不需要携带任何数据

2.8 事件的内部机制

        事件限制外部类只能通过+=向发布者添加订阅方法,并用-=取消订阅,除此之外任何事情不允许做。此外,它还禁止除包容类之外的任何类调用事件。为此,编译器会获取带有event修饰符的public 委托变了,并将委托声明为private,此外还添加两个方法和特殊的事件块。

public class Thermostat {// ...// Declaring the delegate field to save the list of subscribers.private EventHandler<TemperatureArgs> _OnTemperatureChange;public void add_OnTemperatureChange(EventHandler<TemperatureArgs> handler) {System.Delegate.Combine(_OnTemperatureChange, handler);}public void remove_OnTemperatureChange(  EventHandler<TemperatureArgs> handler) {System.Delegate.Remove(_OnTemperatureChange, handler);}//public event EventHandler<TemperatureArgs> OnTemperatureChange//{//    add//    {//        add_OnTemperatureChange(value);//    }//    remove//    {//        remove_OnTemperatureChange(value);//    }//}public class TemperatureArgs : System.EventArgs {public TemperatureArgs(float newTemperature) {}}
}

2.9 自定义事件的实现

        编译器为+=和-=生成的代码是可以自定义的,例如

public class Thermostat {public class TemperatureArgs : System.EventArgs{//….}// Define the delegate data typepublic delegate void TemperatureChangeHandler(object sender, TemperatureArgs newTemperature);// Define the event publisherpublic event TemperatureChangeHandler OnTemperatureChange{add{_OnTemperatureChange = (TemperatureChangeHandler)System.Delegate.Combine(value, _OnTemperatureChange);}remove{_OnTemperatureChange = (TemperatureChangeHandler)System.Delegate.Remove(_OnTemperatureChange, value);}}protected TemperatureChangeHandler _OnTemperatureChange;public float CurrentTemperature{//......}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/175863.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

博弈论学习笔记(2)——完全信息静态博弈

前言 这部分我们学习的是完全信息静态博弈&#xff0c;主要内容包括博弈论的基本概念、战略式博弈、Nash均衡、Nash均衡解的特性、以及Nash均衡的应用。 零、绪论 1、什么是博弈论 1&#xff09;博弈的定义 博弈论&#xff1a;研究决策主体的行为发生直接相互作用时候的决策…

Java架构师软件架构的演化和维护

目录 1 导学2 软件架构演化和定义3 面向对象软件架构演化4 软件架构演化方式的分类5 软件架构演化原则6 软件架构演化评估方法7 大型网站架构演化8 软件架构维护想学习架构师构建流程请跳转:Java架构师系统架构设计 1 导学 2 软件架构演化和定义 软件架构的演化和维护就是对…

Kafka - 异步/同步发送API

文章目录 异步发送普通异步发送异步发送流程Code 带回调函数的异步发送带回调函数的异步发送流程Code 同步发送API 异步发送 普通异步发送 需求&#xff1a;创建Kafka生产者&#xff0c;采用异步的方式发送到Kafka broker 异步发送流程 Code <!-- https://mvnrepository…

飞鼠异地组网工具全网互通实战指南

飞鼠异地组网工具全网互通实战指南 一、飞鼠异地组网工具介绍1.1 飞鼠工具简介1.2 飞鼠工具官网 二、本次实践介绍2.1 本次实践前提2.2 本次实践简介2.3 本次实践环境规划 三、异地组网配置3.1 进入中心控制器节点管理后台3.2 网卡设置3.3 进入子网节点管理后台3.4 网卡设置 四…

项目综合实训,vrrp+bfd,以及策略路由的应用

目录 一&#xff0e; 项目需求 二&#xff0e; Visio设备画图 三&#xff0e; 设备选型 三&#xff0e;vlan规划 四&#xff0e;Ip地址规划 五&#xff0e;实验拓扑图 六&#xff0e;配置过程及结果 项目需求 1.S1作为VLAN10的主网关和根桥&#xff0c;S2作为v…

Pytorch L1,L2正则化

L1正则化和L2正则化是常用的正则化技术&#xff0c;用于在机器学习模型中控制过拟合。它们的主要区别在于正则化项的形式和对模型参数的影响。 L1正则化&#xff08;Lasso正则化&#xff09;&#xff1a; 正则化项形式&#xff1a;L1正则化使用模型参数的绝对值之和作为正则化…

Emscripten + CMakeLists.txt 将 C++ 项目编译成 WebAssembly(.wasm)/js,并编译 Html 测试

背景&#xff1a;Web 端需要使用已有的 C 库&#xff08;使用 CMake 编译&#xff09;&#xff0c;需要将 C 项目编译成 WebAssembly(.wasm) 供 js 调用。 上篇文章《Mac 上安装 Emscripten》 已讲解如何安装配置 Emscripten 环境。 本篇文章主要讲解如何将基于 CMakeLists 配…

Gitee 发行版

Gitee 发行版 1、Gitee 发行版管理2、项目仓库中创建发行版本3、项目中导入3.1 gradle配置3.2 dependencies执行正常&#xff0c;包没有下载 1、Gitee 发行版管理 Gitee 发行版&#xff08;Release&#xff09;管理 2、项目仓库中创建发行版本 按照Gitee官网操作就行 3、项目…

PCIe 访问 EP 配置空间,空间映射详解,BDF 计算偏移

访问 EP 的配置空间方法 内存映射IO 访问 内存访问配置空间 前置知识 PCIe 设备的寻址是按照 BDF 即 Bus-Device-Function 来组织的。访问某个设备则需要根据BDF计算偏移地址。 两种不同的内存访问配置空间方法 类 xilinx&#xff0c;基地址 偏移地址访问 // linux-5.10\…

http1,https,http2,http3总结

1.HTTP 当我们浏览网页时&#xff0c;地址栏中使用最多的多是https://开头的url&#xff0c;它与我们所学的http协议有什么区别&#xff1f; http协议又叫超文本传输协议&#xff0c;它是应用层中使用最多的协议&#xff0c; http与我们常说的socket有什么区别吗&#xff1f; …

【ARM 嵌入式 C 入门及渐进 10 -- 冒泡排序 选择排序 插入排序 快速排序 归并排序 堆排序 比较介绍】

文章目录 排序算法小结排序算法C实现排序方法的稳定性 排序算法小结 C语言中常用的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序。下面我们来一一介绍&#xff1a; 冒泡排序&#xff08;Bubble Sort&#xff09;&#xff1a;冒泡排序是通过比较相邻…

android 8.1 disable unsupported sensor

如果device不支持某种sensor,可以在android/frameworks/base/core/java/android/hardware/SystemSensorManager.java里将其disabled掉。以disable proximity sensor为例。 public SystemSensorManager(Context context, Looper mainLooper) {synchronized(sLock) {if (!sNativ…

MWeb Pro for Mac:博客生成编辑器,助力你的创作之旅

在当今数字化时代&#xff0c;博客已经成为了许多人记录生活、分享知识和表达观点的重要渠道。而要打造一个专业、美观且易于管理的博客&#xff0c;选择一款强大的博客生成编辑器至关重要。今天&#xff0c;我向大家推荐一款备受好评的Mac软件——MWeb Pro。 MWeb Pro是一款专…

flutter深研

https://www.douyin.com/video/7020336319058627853 关闭系统风扇 在 Windows 操作系统上安装和配置 Flutter 开发环境 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 下载Git - Downloading Package 推荐使用迅雷下载 系统配置要求 要想安装和运行 Flutter&#xf…

使用FastAPI部署Ultralytics YOLOv5模型

YOLO是You Only Look Once(你只看一次)的缩写&#xff0c;它具有识别图像中的物体的非凡能力&#xff0c;在日常应用中会经常被使用。所以在本文中&#xff0c;我们将介绍如何使用FastAPI的集成YOLOv5&#xff0c;这样我们可以将YOLOv5做为API对外提供服务。 Python有几个web框…

如何将 ruby 打包类似于jdk在另一台相同架构的机器上面开箱即用

需求 目前工作中使用到了ruby作为java 项目的中转语言&#xff0c;但是部署ruby的时候由于环境的不同会出现安装依赖包失败的问题&#xff0c;如何找到一种开箱即用的方式类似于java 中的jdk内置jvm这种方式 解决 TruffleRuby 完美解决问题&#xff0c;TruffleRuby 是使用 T…

基于STC系列单片机实现外部中断0控制按键调节定时器0产生PWM(脉宽调制)的功能

#define uchar unsigned char//自定义无符号字符型为uchar #define uint unsigned int//自定义无符号整数型为uint sbit PwmOut P1^0;//位定义脉宽调制输出为单片机P1.0脚 uchar PwmTimeCount;//声明脉宽调制时间计数变量 uchar PwmDutyCycle;//声明脉宽调制占空比变量 void Ti…

Apache服务的搭建与配置(超详细版)

前言 Apache是一种常见的Web服务器软件&#xff0c;广泛用于Linux和其他UNIX操作系统上。它是自由软件&#xff0c;可以通过开放源代码的方式进行自由分发和修改。Apache提供了处理静态和动态内容的能力&#xff0c;而且还支持多种编程语言和脚本&#xff0c;如PHP、Python和P…

python数据可视化

内容主要介绍了python模块matplotlib即seaborn数据可视化 matplotlib模块通过import matplotlib.pyplot as plt生成图形&#xff0c;如生成图形没展示&#xff0c;可调用plt.show()方法展示图形&#xff1b; 对于颜色属性设置&#xff0c;既可以使用十六进制颜色表达(#7777aa…

cdrx8和2020哪个版本更好用?有什么区别

经过多年的发展&#xff0c;cdr推出了很多优秀的版本&#xff0c;并顺应时代的发展更新了多项功能。随着cdr推出的软件版本增多&#xff0c;小伙伴们可选择的产品也在增多&#xff0c;那么该怎么选择呢&#xff1f;本文会给大家介绍cdrx8和2020的区别&#xff0c;CDRX8和2020哪…