学习c#的第二十四天

目录

C# 事件(Event)

事件概述

如何订阅和取消订阅事件

以编程方式订阅事件

使用匿名函数订阅事件

取消订阅

如何发布符合 .NET 准则的事件

发布基于 EventHandler 模式的事件

如何在派生类中引发基类事件

如何实现接口事件

如何实现自定义事件访问器

示例


C# 事件(Event)

事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。例如,中断。

C# 中使用事件机制实现线程间的通信。

事件概述

事件是一种在软件开发中常用的机制,用于实现对象间的通信和协作。一个事件有两个主要的参与者:事件发布者和事件订阅者。

事件发布者是引发事件的对象或类,它定义了一个事件以及触发该事件的条件。事件发布者通过调用事件来通知其他对象事件的发生。

事件订阅者是希望接收并处理事件的对象或类。订阅者需要将自己的方法注册到事件上,以便在事件发生时被调用。这个方法被称为事件处理程序,用于处理事件发生时的逻辑。

在.NET类库中,事件通常基于EventHandler委托和EventArgs基类。EventHandler委托定义了事件处理程序方法的签名,它接受两个参数:事件发布者和包含事件数据的EventArgs对象。通过使用标准的EventHandler委托,可以方便地在事件订阅者之间共享事件处理程序。

事件的使用可以带来很多好处。它可以将代码分离为更小、更可维护的部分,并提供了一种松耦合的方式来实现对象间的通信。通过事件,可以实现多个对象对同一个事件作出响应的情况,从而提高了代码的灵活性和可扩展性。

总结起来,事件是一种在软件开发中常用的机制,用于实现对象间的通信和协作。通过事件,事件发布者可以通知事件订阅者事件的发生,并且订阅者可以对事件作出响应。事件基于委托和事件参数类,可以提供更灵活、可维护和可扩展的代码结构。

如何订阅和取消订阅事件

以编程方式订阅事件

在C#中,可以使用+=运算符以编程方式订阅事件。下面是一个简单的示例:

using System;class Program
{static void Main(string[] args){MyEventPublisher publisher = new MyEventPublisher();MyEventHandler handler = new MyEventHandler();// 订阅事件publisher.MyEvent += handler.HandleMyEvent;// 触发事件publisher.TriggerMyEvent();Console.ReadLine();}
}class MyEventPublisher
{// 定义事件public event EventHandler MyEvent;// 触发事件public void TriggerMyEvent(){MyEvent?.Invoke(this, EventArgs.Empty);}
}class MyEventHandler
{// 处理事件public void HandleMyEvent(object sender, EventArgs e){Console.WriteLine("由我的事件处理程序处理的事件");}
}

在上面的示例中,我们定义了一个名为MyEventPublisher的事件发布者类和一个名为MyEventHandler的事件处理程序类。事件发布者类包含一个名为MyEvent的事件,它是基于标准的EventHandler委托定义的。事件处理程序类包含一个名为HandleMyEvent的方法,用于处理事件。

在Main方法中,我们创建了一个事件发布者实例和一个事件处理程序实例。然后,我们使用+=运算符将事件处理程序注册到事件上。最后,我们调用TriggerMyEvent方法触发事件,并在事件处理程序中输出一条消息。

总之,在C#中,可以使用+=运算符以编程方式订阅事件。这使得我们能够动态地向事件添加处理程序,并在不再需要处理程序时将其从事件中删除。

使用匿名函数订阅事件

当需要快速订阅事件且事件处理逻辑相对简单时,使用匿名函数订阅事件是一种方便的方式。下面是一个示例,演示了如何在C#中使用匿名函数订阅事件:

using System;class Program
{static void Main(string[] args){MyEventPublisher publisher = new MyEventPublisher();// 使用匿名函数订阅事件publisher.RaiseCustomEvent += (sender, e) =>{Console.WriteLine("正在处理带有消息的自定义事件: " + e.Message);};// 触发事件publisher.TriggerCustomEvent();Console.ReadLine();}
}class MyEventPublisher
{// 定义事件public event EventHandler<CustomEventArgs> RaiseCustomEvent;// 触发事件public void TriggerCustomEvent(){OnRaiseCustomEvent(new CustomEventArgs("事件已触发"));}protected virtual void OnRaiseCustomEvent(CustomEventArgs e){RaiseCustomEvent?.Invoke(this, e);}
}// 自定义事件参数类
public class CustomEventArgs : EventArgs
{public string Message { get; }public CustomEventArgs(string message){Message = message;}
}

在上面的示例中,我们使用匿名函数来订阅RaiseCustomEvent事件。匿名函数直接定义在订阅操作中,用于处理事件的触发。这样可以避免显式地定义命名的事件处理程序方法,特别适用于只需要进行简单处理的情况。

注意:如果使用匿名函数订阅事件,事件的取消订阅过程将比较麻烦。 这种情况下若要取消订阅,请返回到该事件的订阅代码,将该匿名函数存储在委托变量中,然后将此委托添加到该事件中。 如果必须在后面的代码中取消订阅某个事件,则建议不要使用匿名函数订阅此事件。 有关匿名函数的详细信息,请参阅 Lambda 表达式。

通过匿名函数订阅事件,可以更加简洁地表示事件订阅和处理逻辑,提高代码的可读性和简洁性。

取消订阅

若要防止在引发事件时调用事件处理程序,请取消订阅该事件。 为了防止资源泄露,应在释放订户对象之前取消订阅事件。 在取消订阅事件之前,在发布对象中作为该事件的基础的多播委托会引用封装了订户的事件处理程序的委托。 只要发布对象保持该引用,垃圾回收功能就不会删除订户对象。

在C#中,取消订阅事件可以通过使用减法赋值运算符(-=)来实现。

下面是一个示例,演示了如何取消订阅之前示例中的事件:

using System;class Program
{static void Main(string[] args){MyEventPublisher publisher = new MyEventPublisher();// 定义匿名函数作为事件处理程序EventHandler<CustomEventArgs> eventHandler = (sender, e) =>{Console.WriteLine("正在处理带有消息的自定义事件: " + e.Message);};// 订阅事件publisher.RaiseCustomEvent += eventHandler;// 触发事件publisher.TriggerCustomEvent();// 取消订阅事件publisher.RaiseCustomEvent -= eventHandler;// 再次触发事件publisher.TriggerCustomEvent();Console.ReadLine();}
}class MyEventPublisher
{// 定义事件public event EventHandler<CustomEventArgs> RaiseCustomEvent;// 触发事件public void TriggerCustomEvent(){OnRaiseCustomEvent(new CustomEventArgs("事件已触发"));}protected virtual void OnRaiseCustomEvent(CustomEventArgs e){RaiseCustomEvent?.Invoke(this, e);}
}// 自定义事件参数类
public class CustomEventArgs : EventArgs
{public string Message { get; }public CustomEventArgs(string message){Message = message;}
}

在上面的示例中,我们首先定义了一个匿名函数作为事件处理程序,并将其保存在一个变量eventHandler中。然后,我们使用+=运算符订阅了RaiseCustomEvent事件,并在事件触发后又使用-=运算符取消了对事件的订阅。这样就实现了事件的订阅和取消订阅操作。

通过使用-=运算符取消订阅事件,可以避免事件处理程序继续接收事件通知,从而实现了对事件的动态管理。

注意:所有订户都取消订阅事件后,发行者类中的事件实例将设置为 null。

如何发布符合 .NET 准则的事件

发布基于 EventHandler 模式的事件

发布事件是一种常见的设计模式,它允许一个对象通知其他对象发生了某些事情。在 C# 中,可以使用 EventHandler 模式来实现事件发布。

基于 EventHandler 模式的事件发布包括以下步骤:

  1. 定义自定义事件参数类:通常情况下,事件需要携带一些数据。可以通过自定义事件参数类来实现这个功能。自定义事件参数类必须继承自 EventArgs 类,并且应该包含至少一个属性以保存事件数据。

  2. 声明委托类型:在发布类中声明一个委托类型,用于定义事件处理程序的签名。对于非泛型版本的  EventHandler 委托,无需声明,因为它已经在 System 命名空间中定义。对于泛型版本的 EventHandler<TEventArgs> 委托,则不需要自定义委托类型,而是将事件类型指定为  EventHandler <CustomEventArgs>,其中 CustomEventArgs 是第一步中定义的自定义事件参数类。

  3. 声明事件类型:在发布类中声明一个事件类型,使用步骤 2 中定义的委托类型作为事件处理程序的类型。如果使用泛型版本的 EventHandler<TEventArgs>委托,则可以直接使用  EventHandler <CustomEventArgs> 类型来声明事件。

  4. 引发事件:在发布类中编写一个受保护的虚方法,用于执行实际的事件引发操作。在这个方法中,通过调用事件类型的 Invoke 方法来触发事件,并将自定义事件参数对象传递给事件处理程序。

  5. 订阅事件:在订阅方代码中,使用 += 运算符订阅事件。订阅方可以是类、结构体、接口或委托类型。当事件引发时,所有订阅了该事件的订阅方都会接收到通知,并执行相应的事件处理程序。

下面是一个基于 EventHandler 模式的事件发布的示例代码:

// 定义自定义事件参数类
public class CustomEventArgs : EventArgs
{public string Message { get; private set; }public CustomEventArgs(string message){Message = message;}
}// 声明委托类型
public delegate void CustomEventHandler(object sender, CustomEventArgs e);// 发布类
public class MyEventPublisher
{// 声明事件类型public event CustomEventHandler RaiseCustomEvent;// 引发事件protected virtual void OnRaiseCustomEvent(CustomEventArgs e){RaiseCustomEvent?.Invoke(this, e);}// 触发事件的方法public void TriggerCustomEvent(){OnRaiseCustomEvent(new CustomEventArgs("Hello, World!"));}
}// 订阅方代码
class Program
{static void Main(string[] args){MyEventPublisher publisher = new MyEventPublisher();// 订阅事件publisher.RaiseCustomEvent += Publisher_RaiseCustomEvent;// 触发事件publisher.TriggerCustomEvent();Console.ReadLine();}// 事件处理程序private static void Publisher_RaiseCustomEvent(object sender, CustomEventArgs e){Console.WriteLine(e.Message);}
}

在上面的示例中,我们首先定义了一个自定义事件参数类 CustomEventArgs,它包含一个 Message 属性来保存事件数据。然后,我们声明了一个名为 CustomEventHandler 的委托类型,并用作 MyEventPublisher 类中 RaiseCustomEvent 事件的处理程序类型。在 MyEventPublisher 类中,我们使用 OnRaiseCustomEvent 方法来引发 RaiseCustomEvent 事件,然后在 TriggerCustomEvent 方法中调用该方法。

在 Main 方法中,我们创建 MyEventPublisher 实例 publisher,并使用 += 运算符订阅 RaiseCustomEvent 事件。之后,我们调用 publisher 的 TriggerCustomEvent 方法来触发事件。当 RaiseCustomEvent 事件被触发时,我们定义的事件处理程序 Publisher_RaiseCustomEvent 将被调用,并输出 "Hello, World!" 字符串到控制台。

如何在派生类中引发基类事件

在派生类中引发基类事件的过程与在基类中引发事件的过程类似,只需要通过基类的事件来触发即可。下面是在派生类中引发基类事件的基本步骤:

  1. 在派生类中声明一个新的事件,或者可以选择重用基类的事件。
  2. 创建一个方法来触发基类事件。

下面是一个示例代码,演示了如何在派生类中引发基类事件:

using System;// 基类
public class BaseClass
{// 声明基类事件类型public event EventHandler BaseEventRaised;// 引发基类事件的方法protected virtual void OnBaseEventRaised(EventArgs e){BaseEventRaised?.Invoke(this, e);}
}// 派生类
public class DerivedClass : BaseClass
{public void DoSomething(){// 在派生类中进行一些操作// 触发基类事件OnBaseEventRaised(EventArgs.Empty);}
}// 主程序
class Program
{static void Main(string[] args){DerivedClass derived = new DerivedClass();// 订阅基类事件derived.BaseEventRaised += BaseEvent_Handler;// 在派生类中触发事件derived.DoSomething();Console.ReadLine();}// 基类事件处理程序private static void BaseEvent_Handler(object sender, EventArgs e){Console.WriteLine("在派生类中处理的基事件。");}
}

在上面的示例中,我们首先定义了一个基类 BaseClass,它包含一个名为 BaseEventRaised 的事件以及相应的触发方法 OnBaseEventRaised。然后,我们创建了一个派生类 DerivedClass,在该类中我们调用了基类事件触发方法 OnBaseEventRaised 来触发基类事件。

在主程序中,我们创建了 DerivedClass 的实例 derived,并订阅了基类的事件 BaseEventRaised。之后,我们调用 derived 的 DoSomething 方法来触发事件。当基类事件被触发时,我们定义的事件处理程序 BaseEvent_Handler 将被调用,并输出 "在派生类中处理的基事件。" 到控制台。

通过这种方式,派生类可以很容易地引发基类中已定义的事件,从而实现事件传播和处理。

如何实现接口事件

在 C# 中,接口可以定义事件,需要使用 event关键字来标记接口中的事件。实现接口事件的类必须提供事件的实现。下面是实现接口事件的基本步骤:

  1. 定义一个包含事件的接口,并使用 event 关键字来标记事件。

  2. 实现接口的类必须提供事件的实现。为此,可以在实现类中声明一个事件,并将其与接口中的事件关联起来。

  3. 在实现类中引发事件的方法。

下面是一个示例代码,演示了如何实现接口事件:

using System;// 定义包含事件的接口
public interface IMyInterface
{event EventHandler MyEventRaised;
}// 实现接口的类
public class MyClass : IMyInterface
{// 声明事件public event EventHandler MyEventRaised;// 引发事件的方法public void RaiseEvent(){OnMyEventRaised(EventArgs.Empty);}// 触发事件的方法protected virtual void OnMyEventRaised(EventArgs e){MyEventRaised?.Invoke(this, e);}
}// 主程序
class Program
{static void Main(string[] args){MyClass myClass = new MyClass();// 订阅事件myClass.MyEventRaised += MyEventHandler;// 触发事件myClass.RaiseEvent();Console.ReadLine();}// 事件处理程序private static void MyEventHandler(object sender, EventArgs e){Console.WriteLine("我的事件处理好了。");}
}

在上面的示例中,我们首先定义了一个包含事件的接口 IMyInterface,并使用 event 关键字来标记事件。然后,我们创建了一个实现接口的类 MyClass,在该类中声明了一个名为 MyEventRaised 的事件。在 MyClass 中,我们使用 OnMyEventRaised 方法来触发 MyEventRaised 事件。

在主程序中,我们创建了 MyClass 的实例 myClass,并订阅了 MyEventRaised 事件。之后,我们调用 myClass 的 RaiseEvent 方法来触发事件。当 MyEventRaised 事件被触发时,我们定义的事件处理程序 MyEventHandler 将被调用,并输出 "我的事件处理好了。" 到控制台。

通过这种方式,我们可以在接口中定义事件,并在实现类中提供事件的实现。因此,可以轻松地将事件的行为分离到不同的类和接口中。

如何实现自定义事件访问器

事件是一种特殊的多播委托,只能从声明它的类中进行调用。 客户端代码通过提供对应在引发事件时调用的方法的引用来订阅事件。 这些方法通过事件访问器添加到委托的调用列表中,事件访问器类似于属性访问器,不同之处在于事件访问器命名为 add 和 remove。 在大多数情况下,无需提供自定义事件访问器。 如果代码中没有提供自定义事件访问器,编译器将自动添加它们。 但在某些情况下,可能需要提供自定义行为。

示例

下面的示例演示如何实现自定义的 add 和 remove 事件访问器来控制事件处理程序的添加和移除行为。

using System;public delegate void MyEventHandler(object sender, EventArgs e);public class MyClass
{private event MyEventHandler myEvent;public event MyEventHandler MyEvent{add{Console.WriteLine("添加事件处理程序");myEvent += value;}remove{Console.WriteLine("正在删除事件处理程序");myEvent -= value;}}public void DoSomething(){Console.WriteLine("正在做某事。。。");myEvent?.Invoke(this, EventArgs.Empty);}
}public class Program
{static void Main(string[] args){MyClass myObj = new MyClass();myObj.MyEvent += MyEventHandler1;myObj.MyEvent += MyEventHandler2;myObj.DoSomething();myObj.MyEvent -= MyEventHandler2;myObj.DoSomething();Console.ReadLine();}private static void MyEventHandler1(object sender, EventArgs e){Console.WriteLine("事件处理程序处理的事件1");}private static void MyEventHandler2(object sender, EventArgs e){Console.WriteLine("事件处理程序处理的事件2");}
}

在上面的示例中,我们首先声明了一个自定义委托MyEventHandler,它定义了事件处理程序的签名。

然后,我们在MyClass类中声明了一个私有的MyEventHandler类型的事件myEvent。接下来,在MyEvent属性中定义了自定义的事件访问器。

在add访问器中,我们输出添加事件处理程序的消息,并将事件处理程序添加到myEvent事件中。在remove访问器中,我们输出移除事件处理程序的消息,并将其从myEvent事件中移除。

通过自定义事件访问器,我们可以在添加和移除事件处理程序时执行自定义的逻辑。在上面的示例中,我们简单地输出一条消息,但你可以根据需要在这些访问器中添加更复杂的逻辑。

最后,在主程序中,我们创建了一个MyClass的实例myObj,并订阅了MyEvent事件。在调用myObj.DoSomething()时,事件处理程序被调用,并输出相应的消息。然后,我们使用-=操作符将一个事件处理程序从事件中移除,并再次调用myObj.DoSomething(),只有一个事件处理程序被调用。

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

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

相关文章

C语言--每日选择题--Day26

第一题 1.在C语言中&#xff0c;表示一次性地给数组a的10元素赋值&#xff08;&#xff09; int a[10];scanf&#xff08;"%d"&#xff0c;a&#xff09;; A&#xff1a;正确 B&#xff1a;错误 答案及解析 B 我们知道单独的数组名就是首元素地址&#xff0c;但是也有…

一文从Vue2过渡到Vue3

文章目录 Vue3简介创建Vue3.0工程使用 vue-cli 创建使用 vite 创建Vue3工程结构变化 常用 Composition API拉开序幕的setupref函数reactive函数Vue3.0中的响应式原理vue2.x的响应式Vue3.0的响应式 reactive对比refsetup的两个注意点计算属性与监视computed函数watch函数watchEf…

Pytorch中的gather的理解和用法

Pytorch中的gather的理解和用法 这个Gather的用法花费了点时间&#xff0c;我相信很多人一开始不太懂。 跟着我简单理解。 首先样例是&#xff1a; tensor([[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])然后index: [[2, 1, 0]]然后执行的代码&#xff1a; tensor_0.gather(0…

享受更健康的睡眠,dido P1S智能手环体验

如今很多人都有严重的失眠困扰&#xff0c;像是因为平时工作非常繁忙&#xff0c;每天回到家后已经很晚了&#xff0c;或者是睡前长时间刷手机&#xff0c;躺在床上辗转反侧&#xff0c;晚上就很难入睡&#xff0c;脑海中一片混乱&#xff0c;休息的质量就很差。我最近尝试了一…

人工智能关键技术决定机器人产业的前途

人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;是指让计算机或机器具有类似于人类的智能和学习能力的技术。人工智能技术与机器人技术的结合将改变传统的机器人行业格局&#xff0c;就像智能手机对传统手机的颠覆一样。本文从人工智能技术的发展趋势、…

ASIWebPage数据库抓取代码示例

objective-c #import "ASIWebPageRequest.h" int main(int argc, const char * argv[]) { autoreleasepool { // 创建并设置 NSURL *代理URL [NSURL URLWithString:""]; ASIHTTPRequest *request [ASIHTTPRequest requestW…

jsoup登录日志平台后调企业微信机器人自动发送错误日志告警

一、需求&#xff1a;错误日志Top10告警发送 二、需求分解 jsoup实现登录&#xff0c;获取到cookie和token等用户鉴权信息获取接口相应的key值调用日志平台错误日志Top榜接口&#xff0c;查询到结果集调用企业微信机器人发送消息接口加上定时任务&#xff0c;可以实现定时发送…

java多线程-扩展知识二:线程的生命周期

1、生命周期 生命周期有广义与狭义之分&#xff0c;狭义为生命科学术语&#xff0c;指包括人类在内的一切动物由出生到死亡经历的生命全程。广义的生命周期泛指自然界与人类社会各种客观事物的阶段性变化及规律&#xff0c;如家庭生命周期、产品生命周期等。本义即狭义的生命周…

任务管理器怎么打开?4个方法快速打开!

“我想进入电脑任务管理器中对某些应用进行设置&#xff0c;但是我不知道应该怎么进入任务管理器中。有什么方法可以快速进入任务管理器吗&#xff1f;” 任务管理器是Windows操作系统中一个强大的工具&#xff0c;可以让你监控和管理计算机上运行的进程、应用程序和性能。当我…

FLASK博客系列5——模板之从天而降

我们啰啰嗦嗦讲了4篇&#xff0c;都是在调接口&#xff0c;啥时候能看到漂亮的页面呢&#xff1f;别急&#xff0c;今天我们就来实现。 来我们先来实现一个简单的页面。不多说&#xff0c;上代码。 app.route(/) def index():user {username: clannadhh}return <html>&…

解决方案:新版WPS-右键粘贴值到可见单元格没有了

旧版WPS&#xff0c;右键就能出现 但是新版WPS不是在这里&#xff08;方法1&#xff09; 新版WPS&#xff08;方法2&#xff09; 视频详细教程链接&#xff1a;解决方案&#xff1a;新版WPS-右键粘贴值到可见单元格没有了 -- 筛选后复制公式粘贴为数值_哔哩哔哩_bilibili

智能优化算法应用:基于飞蛾扑火算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于飞蛾扑火算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于飞蛾扑火算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.飞蛾扑火算法4.实验参数设定5.算法结果6.参考…

数智融合 开启金融数据治理新时代

11月24日&#xff0c;由上海罗盘信息科技有限公司&#xff08;罗盘科技&#xff09;主办&#xff0c;北京酷克数据科技有限公司&#xff08;酷克数据&#xff09;支持协办的“博学近思 切问治理”数据治理分享会在上海成功举行。 本次会议深度聚焦金融行业数智化转型&#xff…

FPGA模块——DA转换模块(AD9708类)

FPGA模块——DA转换模块&#xff08;AD9708类&#xff09; AD9708/3PD9708代码 AD9708/3PD9708 由于电路接了反相器&#xff0c;所以对应就不一样了。 电路图&#xff1a; 代码 在ROM中存入要输出的波形数据&#xff1a; 用软件生成各个对应的点。 给DA转换器一个时钟&…

网络篇---第四篇

系列文章目录 文章目录 系列文章目录前言一、TCP 如何保证可靠性二、OSI 的七层模型都有哪些?三、浏览器中输入:“www.woaijava.com”之后都发生了什么?请详细阐述前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站…

关于Unity中字典在Inspector的显示

字典在Inspector的显示 方法一&#xff1a;实现ISerializationCallbackReceiver接口 《unity3D游戏开发第二版》记录 在编辑面板中可以利用序列化监听接口特性对字典进行序列化。 主要继承ISerializationCallbackReceiver接口 实现OnAfterDeserialize() OnBeforeSerialize() …

C# WPF上位机开发(第一个应用)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 万事开头难&#xff0c;很多事情都是难在第一步。走出了这第一步&#xff0c;回过头看以前走的每一步&#xff0c;发现其实也不难。用c# wpf编写界…

VSD Viewer for Mac(Visio绘图文件阅读器)

VSD Viewer for Mac版是mac上一款非常强大的Visio绘图文件阅读器&#xff0c;它为打开和打印Visio文件提供了简单的解决方案。可以显示隐藏的图层&#xff0c;查看对象的形状数据&#xff0c;预览超链接。还可以将Visio转换为包含图层&#xff0c;形状数据和超链接的PDF文档。 …

【C/PTA —— 12.指针1(课外实践)】

C/PTA —— 12.指针1&#xff08;课外实践&#xff09; 一.函数题6-1 删除字符串中数字字符6-2 找最大值及其下标6-3 求两数平方根之和6-4 求一组数中的最大值、最小值和平均值6-5 两个4位正整数的后两位互换6-6 判断回文字符串 二.程序题7-1 求矩阵每行元素的和 一.函数题 6-…

5.golang字符串的拆解和拼接

字符串是 Go 中的字节切片。可以通过将一组字符括在双引号中来创建字符串" "。Go 中的字符串是兼容Unicode编码的&#xff0c;并且是UTF-8编码的。 访问字符串的单个字节或字符 由于字符串是字节切片&#xff0c;因此可以访问字符串的每个字节。 func printStr(s …