当前位置: 首页 > news >正文

高级C#技术(二)

前言

本章为高级C#技术的第二节也是最后一节。前一节在下面这个链接

高级C#技术icon-default.png?t=N7T8https://blog.csdn.net/qq_71897293/article/details/134930989?spm=1001.2014.3001.5501

匿名类型

匿名类型如其名,匿名的没有指定变量的具体类型。

举个例子:

1 创建一个类

    public class Student{public int Age { get; set; }public int Weight { get; set; }public string Name { get; set; }}

2 创建一个Student的实例化,并且将这个类的所有成员进行了一个初始化

 Student student = new Student{Age = 10,Weight = 100,Name = "",};

示例解释:当前代码的写法是上一节提到的对象初始化器。

创建一个匿名类型:

var Variable = new
{Age = 10,Weight = 100,Name = "",
};

示例解释:

        1 使用了var 关键字 ,因为匿名函数没有可以使用的标识符(类型)
        2 new 关键字后没有举明具体类型,等于是告诉编译器我们需要使用匿名类型
        3 在系统的智能提示中,我们鼠标放在变量类型上都会显示相应的变量类型。 而匿名类型则是用a来表示。       

图例:

注意:当前匿名类型不是创建了Student的实例,而是一个自定义的匿名类型两者没有关系。

使用匿名类型:

var s = Variable.Age;//可以通过创建的匿名类型,拿到匿名类型的成员,但这些数据是只读的

注意:可以通过创建的匿名类型,拿到匿名类型的成员,但这些数据是只读的 

扩展(此处引入书上源码)

var animals = new[]
{new { Name = "Benjamin", Age = 42, Weight = 185 },new { Name = "Benjamin", Age = 42, Weight = 185 },new { Name = "Andrea", Age = 46, Weight = 109 }
};
WriteLine(animals[0].ToString());
WriteLine(animals[0].GetHashCode());
WriteLine(animals[1].GetHashCode());
WriteLine(animals[2].GetHashCode());
WriteLine(animals[0].Equals(animals[1]));
WriteLine(animals[0].Equals(animals[2]));
WriteLine(animals[0] == animals[1]);
WriteLine(animals[0] == animals[2]);
ReadKey();

示例解释:

        当前的var animals=new [] 这里是使用了我们前面的类型推理,在当前这个匿名类型对象数组当中,我们创建了多个匿名类型。然后调用了几种不同的方法后输出结果。

        GetHashCode:返回一个对象的哈希码(整数数值)可以用于储存在哈希表等数据结构中。在数组当中的前两个有着相同的属性值,即返回的哈希值是相同的。

        Equals:匿名函数上就是比较一个对象的每个属性与另一个的对应属性值是否相同。如果相同则返回true。

        ==:比较比较对象引用。与方法Equals一致,但在匿名函数中的Equals不是一致。     

输出结果:

{ Name = Benjamin, Age = 42, Weight = 185 }
-1144474565
-1144474565
-977821549
True
False
False
False

提问:创建匿名类型时,如果是是多个相同类型的参数,会创建多个匿名类型吗?像我们前面扩展中创建的方式。


答:不会,会创建同一个匿名类型的多个实例。

动态查找

        动态查找:1 希望使用C#处理另一种语言创建的对象。2 处理未知类型的C#对象,如前一章使用了简单的反射来访问与类型关联的特性。

动态类型

动态类型我不好解释我们直接看它的定义方式,以及使用方式。

定义 (关键字dynamic)  :

public dynamic dongtaitype;

注意:        

        上述代码我们就已经定义了一个动态类型,但它与我们前面的var关键字不同var的关键字它并不是一个类型,而我们这里定义的'dongtaitype'它叫动态类型。一旦有了动态类型我们就可以继续访问其他成员。 

namespace MY
{class Program{public static dynamic dongtaitype;static void Main(){dongtaitype.ToString();}}
}

示例解释:我们这里直接用当前我们创建的动态类型直接调用了ToString方法。


注意:

        我这里并没有实现ToString方法也并没有给我们的动态类型进行一个初始化。所以它现在的值是"null" 。但编译器并不会报错。编译器还是会在运行的时候去调用这个方法,但当前变量是null所以这无法调用,编译器会抛出异常。


警告:我们在使用动态类型的情况下,我们尽量在只能使用动态类型的情况下再去使用它。如非.net对象,我的理解就是非C#语言创建的对象

接下来我大家看一个动态类型的例子(引在书上示例):

using Microsoft.CSharp.RuntimeBinder;
using static System.Console;
namespace My
{class MyClass1{public int Add(int var1, int var2) => var1 + var2;}class MyClass2 { }class Program{static int callCount = 0;static dynamic GetValue(){if (callCount++ == 0){return new MyClass1();}return new MyClass2();}static void Main(string[] args){try{dynamic firstResult = GetValue();dynamic secondResult = GetValue();WriteLine($"firstResult is: {firstResult.ToString()}");WriteLine($"secondResult is: {secondResult.ToString()}");WriteLine($"firstResult call: {firstResult.Add(2, 3)}");WriteLine($"secondResult call: {secondResult.Add(2, 3)}");}catch (RuntimeBinderException ex){WriteLine(ex.Message);}ReadKey();}}
}

示例解释:

        当前我们定义了两个类一个是MyClass1 一个是MyClass2 。其中MyClass1 当中我们定义了一个Add的一个方法。MyClass2 我们没有定义任何成员。在程序主入口Main函数当中我们定义了两个动态类型并且调用了返回动态类型的方法。那么在我们第一次调用GetValue这个方法的时候它会为我们返回一个MyClass1 的实例。在我们第二次调用的时候会返回一个MyClass2 的实例。随后我们使用我们拿到的动态类型去调用我们的ToString方法在这个我们是可以调用的,它实际是一个类型的实例化,当然也可以调用我们父类的ToString方法。那么重要的是我们输出语句的第三个输出语句,我们调用了一个Add的方法我们当前第一个动态类型是没有问题。但是下面那个MyClass2 的实例。这个动态类型它是无法调用因为它根本就没有当前方法。所以这里我们会抛出一个异常会提示“My.MyClass2”未包含“Add”的定义。 然后我们再对抛出的异常进行一个打印异常消息随后这个代码就结束了 

 高级方法参数

高级方法参数:允许使用命名参数和可选参数对方法的一个使用和定义

可选参数

定义方法时某些参数是可选的,而并非像常见方法的参数,要进行重载才能实现相同效果。

示例:

using System;
using Microsoft.CSharp.RuntimeBinder;
using static System.Console;
namespace My
{class Program{static void Main(string[] args){WStudent("zhangsan", 15);WStudent("李四");ReadKey();}#region 重载实现static void WrileStudent(string str){WriteLine(str);}static void WrileStudent(string str, int age){WriteLine(str + age);}#endregion#region 可选参数static void WStudent(string str, int age = 0){WriteLine(str + age);}#endregion}
}

示例解释:

        当前我们给”WrileStudent“方法提供了两个重载的方法。当然我们在下面又定义了一个效果相同的一个方法。其中int age=0 我们在这里其实就是定义了一个可选参数。我们在需要使用它的时候则给它传值,不需要可以直接忽略不传。

1 可选参数的值:默认值必须是:字面值、常量值、默认值类型值。

2 Optional特性:我们也可以使用当前特性定义可选参数

  static void WStudent(string str, [Optional] string ll, int age = 0){WriteLine(str + age+ ll);}

3 可选参数的顺序 :

  • 可选参数必须位于方法参数列表的末尾
  • 没有默认值的参数不能放在有默认值参数的后面 

命名参数

  //使用static void Main(string[] args){WStudent("李四", age: 10, ll: "");ReadKey();}//定义static void WStudent(string str, [Optional] string ll, int age = 0,int A=0,int B=10){WriteLine(str + age + ll);}

注意:使用方式时参数名+":"+值。


提示: 

        1 使用命令参数时可以指定需要的任意多个参数,而且参数的顺序是任意的。

        2 命名参数也是可选的 

        3 当方法签名中有多个可选参数和一些必选参数时,可以先指定必选参数,然后再指定需要使用到的可选参数。

Lambda表达式

         Lambda表达式是一种结构,简化C#编程的某些方面。Lambda表达式与其他的C#语言特性结合起来使用及其有用。如和匿名方法结合使用。

提示:匿名方法中 我们不要使用:My.lapsed+=Wrile; 这里是直接将一个方法赋值给事件。这样做会使代码更难理解也不清楚会发生什么  

把lambda表达式用于匿名方法

        在前面我们介绍了匿名方法的使用这里我将演示用lambda表达式替换匿名方法。在使用之前我有必要和你介绍lambda表达式的组成成分,分为三步。

第一部分:在括号当中放参数列表

第二部分:运算符

第三部分:我们的C#语句

举个例子:

using System;
using System.Timers;
namespace My
{class Program{static void Main(string[] args){Timer timer=new Timer(100);timer.Elapsed += delegate (object sender, ElapsedEventArgs e){//事件处理代码};//lambda 表达式替换匿名函数timer.Elapsed += (sender, e) => Console.Write("Hello");}}
}

示例解释:

        当前我们就做了一个lambda表达式替换匿名函数的一个示例。其中括号当中的就是我们的参数列表其他的部分也是按照我们上面所提到的三个部分所组成我们一个完整的lambda表达式 

Lambda表达式的参数

        Lambda表达式使用类型推理功能来确定所传递的参数类型。我们上述的一个示例并没有指定类型的情况下我们就是使用的它的一个类型推理功能,一个称为隐式类型化的Lambda表达式但如果我们指定了参数列表,当中的参数类型。那么它就被称为一个显示的Lambda表达式 

举个例子:

//显式lambda 表达式
timer.Elapsed += (object sender, ElapsedEventArgs e) => Console.Write("Hello");
//隐式lambda 表达式
timer.Elapsed += (sender, e) => Console.Write("Hello");

注意:

        1 在表达式当中你要么就全部显式类型要么就全部隐式类型。不能一个显式类型一个隐式类型 

        2 定义没有参数的 Lambda 表达式 则使用空括号来表达

举个例子:(sender) => Console.Write("Hello");

        3 定义单个参数的 Lambda 表达式 则不需要用括号  sender => Console.Write("Hello");

Lambda表达式的语句体

        我们其实可以在表达式的语句体中包含多个语句,为此我们就可以用花括号将我们的代码块放在其中。

举个例子:

timer.Elapsed += (object sender, ElapsedEventArgs e)=>
{ //放入代码块
};

        当我们lambda表达式 需要返回除void类型的其他类型,那么我们就要用上关键字 return 进行返回值,和我们在方法中一样。

提示(引入书上原文):如果需要多个语句则定义一个单独的非并匿名方法来代替lambda表达式比较好。

Lambda表达式用作委托和表达式树

        Lambda表达式其实是一个委托,你可以把Lambda表达式赋值给一个委托类型的变量。如我们前面的几个示例一样。但是在system名称空间中已经为我们提供了一些委托类型。所以在很多情况下我们都可以使用这些泛型委托类型而不必定义自己的泛型委托类型。

举例:

泛型类型参数列表个数返回类型
Action表示Lambda表达式     不带参数Void
Action<>表示Lambda表达式最多八个参数Void
Func<>表示Lambda表达式最多八个参数不是Void

相关文章:

高级C#技术(二)

前言 本章为高级C#技术的第二节也是最后一节。前一节在下面这个链接 高级C#技术https://blog.csdn.net/qq_71897293/article/details/134930989?spm1001.2014.3001.5501 匿名类型 匿名类型如其名&#xff0c;匿名的没有指定变量的具体类型。 举个例子&#xff1a; 1 创建…...

【性能测试】基础知识篇-压力模型

常见压力模式 并发模式&#xff08;即虚拟用户模式&#xff09;和RPS模式&#xff08;即Requests Per Second&#xff0c;每秒请求数&#xff0c;吞吐量模式&#xff09;。 本文介绍这两种压力模式的区别&#xff0c;以便根据自身业务场景选择更合适的压力模式。 并发模式 …...

springboot-redis设置定时触发任务详解

最近研究了一下“redis定时触发”&#xff0c;网上查了查资料&#xff0c;这里记录一下。 从Redis 2.8.0开始&#xff0c;Redis加入了发布/订阅模式以及键空间消息提醒&#xff08;keyspace notification&#xff09;功能。键空间消息提醒提供了允许客户端通过订阅指定信道获取…...

Video anomaly detection with spatio-temporal dissociation 论文阅读

Video anomaly detection with spatio-temporal dissociation 摘要1.介绍2.相关工作3. Methods3.1. Overview3.2. Spatial autoencoder3.3. Motion autoencoder3.4. Variance attention module3.5. Clustering3.6. The training objective function 4. Experiments5. Conclusio…...

svn 安装

安装系统 ubuntu 22 安装命令&#xff1a; sudo apt-get install subversion 创建第一个工程&#xff1a; 创建版本库、项目 1、先创建svn根目录文件夹 sudo mkdir /home/svn 2、创建项目的目录文件夹 sudo mkdir /home/svn/demo_0 svnadmin create /home/svn/demo_0 配置&a…...

slurm 23.11.0集群 debian 11.5 安装

slurm 23.11.0集群 debian 11.5 安装 用途 Slurm(Simple Linux Utility for Resource Management&#xff0c; http://slurm.schedmd.com/ )是开源的、具有容错性和高度可扩展的Linux集群超级计算系统资源管理和作业调度系统。超级计算系统可利用Slurm对资源和作业进行管理&a…...

ffmpeg可以做什么

用途 FFmpeg是一个功能强大的多媒体处理工具&#xff0c;可以处理音频和视频文件。它是一个开源项目&#xff0c;可在各种操作系统上运行&#xff0c;包括Linux、Windows和Mac OS X等。以下是FFmpeg可以做的一些主要任务&#xff1a; 转换媒体格式&#xff1a;可将一个媒体格式…...

一种缩小数据之间差距的算法

先上代码&#xff1a; /** * 缩小数据之间的差距&#xff0c;但是大小关系不变的方法* param {Array} features */function minMaxData(data) {for (let i 0; i < data.length; i) {const f data[i];const x f[1];const yf[2];//此处5根据实际情况设置const y2 Math.pow(…...

【Axure RP9】动态面板使用------案例:包括轮播图和多方式登入及左侧菜单栏案例

目录 一 动态面板简介 1.1 动态面板是什么 二 轮播图 2.1 轮播图是什么 2.2 轮播图应用场景 2.3 制作实播图 三 多方式登入 3.1多方式登入是什么 3.3 多方式登入实现 四 左侧菜单栏 4.1左侧菜单栏是什么 4.2 左侧菜单栏实现 一 动态面板简介 1.1 动态面板是什么…...

在接口实现类中,加不加@Override的区别

最近的软件构造实验经常需要设计接口&#xff0c;我们知道Override注解是告诉编译器&#xff0c;下面的方法是重写父类的方法&#xff0c;那么单纯实现接口的方法需不需要加Override呢&#xff1f; 定义一个类实现接口&#xff0c;使用idea时&#xff0c;声明implements之后会…...

优质全套SpringMVC教程

三、SpringMVC 在SSM整合中&#xff0c;MyBatis担任的角色是持久层框架&#xff0c;它能帮我们访问数据库&#xff0c;操作数据库 Spring能利用它的两大核心IOC、AOP整合框架 1、SpringMVC简介 1.1、什么是MVC MVC是一种软件架构的思想&#xff08;不是设计模式-思想就是我们…...

微信小程序---使用npm包安装Vant组件库

在小程序项目中&#xff0c;安装Vant 组件库主要分为如下3步: 注意&#xff1a;如果你的文件中不存在pakage.json&#xff0c;请初始化一下包管理器 npm init -y 1.通过 npm 安装(建议指定版本为1.3.3&#xff09; 通过npm npm i vant/weapp1.3.3 -S --production 通过y…...

GPT-4V被超越?SEED-Bench多模态大模型测评基准更新

&#x1f4d6; 技术报告 SEED-Bench-1&#xff1a;https://arxiv.org/abs/2307.16125 SEED-Bench-2&#xff1a;https://arxiv.org/abs/2311.17092 &#x1f917; 测评数据 SEED-Bench-1&#xff1a;https://huggingface.co/datasets/AILab-CVC/SEED-Bench SEED-Bench-2&…...

数据库_mongoDB

1 介绍 MongoDB 是一种 NoSQL 数据库&#xff0c;它将每个数据存储为一个文档&#xff0c;这里的文档类似于 JSON/BSON 对象&#xff0c;具体数据结构由键值&#xff08;key/value&#xff09;对组成。字段值可以包含其他文档&#xff0c;数组及文档数组。其数据结构非常松散&…...

Layui实现自定义的table列悬停事件并气泡提示信息

1、概要 使用layui组件实现table的指定列悬停时提示信息&#xff0c;因为layui组件中没有鼠标悬停事件支持&#xff0c;所以需要结合js原生事件来实现这个功能&#xff0c;并结合layui的tips和列的templte属性气泡提示实现效果。 2、效果图 3、代码案例 <!DOCTYPE html&g…...

Tomcat从认识安装到详细使用

文章目录 一.什么是Tomact?二.Tomcat的安装1.下载安装包2.一键下载3.打开Tomcat进行测试4.解决Tomcat中文服务器乱码 三.Tomcat基本使用1.启动与关闭Tomcat2.Tomcat部署项目与浏览器访问项目 四.Tomcat操作中的常见问题1.启动Tomcat后&#xff0c;启动窗口一闪而过&#xff1f…...

07-Eventing及实践

1 Knative Eventing的相关组件 Knative Eventing具有四个最基本的组件&#xff1a;Sources、Brokers、Triggers 和 Sinks 事件会从Source发送至SinkSink是能够接收传入的事件可寻址&#xff08;Addressable&#xff09;或可调用&#xff08;Callable&#xff09;资源 Knative S…...

Linux下Netty实现高性能UDP服务

前言 近期笔者基于Netty接收UDP报文进行业务数据统计的功能&#xff0c;因为Netty默认情况下处理UDP收包只能由一个线程负责&#xff0c;无法像TCP协议那种基于主从reactor模型实现多线程监听端口&#xff0c;所以笔者查阅网上资料查看是否有什么方式可以接收UDP收包的性能瓶颈…...

Ubuntu 22.04 Tesla V100s显卡驱动,CUDA,cuDNN,MiniCONDA3 环境的安装

今天来将由《蓝创精英团队》带来一个Ubuntu 显卡环境的安装&#xff0c;主要是想记录下来&#xff0c;方便以后快捷使用。 主要的基础环境 显卡驱动 (nvidia-smi)CUDA (nvidia-smi 可查看具体版本)cuDNN (cuda 深度学习加速库)Conda python环境管理(Miniconda3) Nvidia 驱动…...

FFmpeg转码流程和常见概念

视频格式&#xff1a;mkv&#xff0c;flv&#xff0c;mov&#xff0c;wmv&#xff0c;avi&#xff0c;mp4&#xff0c;m3u8&#xff0c;ts等等 FFmpeg的转码工具&#xff0c;它的处理流程是这样的&#xff1a; 从输入源获得原始的音视频数据&#xff0c;解封装得到压缩封装的音…...

【01】GeoScene生产海图或者电子航道图

1.1 什么是电子海图制图模块 GeoScene海事模块是一个用于管理和制作符合国际水文组织&#xff08;IHO&#xff09;S-100系列标准和S-57标准的海事数据的系统。提供了S-100和S-57工具&#xff0c;用于加载基于S-100的要素目录、创建基于S-57传输结构的数据、输入数据、符号化数…...

TWS蓝牙耳机的船运模式

TWS蓝牙耳机的船运模式 是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,+群赠送语音信号处理降噪算法,蓝牙耳机音频,DSP音频项目核心开发资料, TWS蓝牙耳机的船运模式是指在将耳机从一个地方运送到另一个地方时,…...

Vue系列之指令 v-html

文章の目录 1、v-html指令2、基本用法写在最后 1、v-html指令 v-html 指令类似于 v-text 指令&#xff0c;它与 v-text 区别在于 v-text 输出的是纯文本&#xff0c;浏览器不会对其再进行html解析&#xff0c;但v-html会将其当html标签解析后输出&#xff0c;类似于 JavaScrip…...

Mac如何安装stable diffusion

今天跟大家一起在Mac电脑上安装下stable diffusion&#xff0c;在midjourney等模型收费的情况下如何用自己的电脑算力用上免费的画图大模型呢&#xff1f;来吧一起实操起来 一、安装homebrew 官网地址&#xff1a;Homebrew — The Missing Package Manager for macOS (or Lin…...

Kubernetes (k8s) 快速认知

应用部署方式 传统部署时代 早期的时候&#xff0c;各个组织是在物理服务器上运行应用程序。缺点 资源分配问题&#xff1a; 无法限制在物理服务器中运行的应用程序资源使用 维护成本问题&#xff1a; 部署多个物理机&#xff0c;维护许多物理服务器的成本很高 虚拟化部署时…...

Electron V28主进程与渲染进程互相通信总结

本文示例采用ElectronVue3TS编写&#xff0c;请读者理顺思路&#xff0c;自行带入自己的项目。 注&#xff1a; 读本文前请先搞懂什么是主进程&#xff0c;什么是渲染进程。 在Electron中有着ipcMain和ipcRenderer、contextBridge模块&#xff0c;以及创建窗口对象上的webCont…...

MySQL主从复制详解

目录 1. 主从复制的工作原理 1.1. 主从复制的角色 1.2. 主从复制的流程 2. 配置MySQL主从复制 2.1. 确保主服务器开启二进制日志 2.2. 设置从服务器 2.3. 连接主从服务器 2.4. 启动复制 3. 主从复制的优化与注意事项 3.1. 优化复制性能 3.2. 注意复制延迟 3.3. 处理…...

verilog基础语法-计数器

概述&#xff1a; 计数器是FPGA开发中最常用的电路&#xff0c;列如通讯中记录时钟个数&#xff0c;跑马灯中时间记录&#xff0c;存储器中地址的控制等等。本节给出向上计数器&#xff0c;上下计数器以及双向计数器案例。 内容 1. 向上计数器 2.向下计数器 3.向上向下计数…...

有SCL,SDA,TRIG,I2C的元器件是什么?在哪找?proteus

寻找方法&#xff1a;...

再谈低代码开发——值得所有程序设计和开发者重视的建议!

前几天看到关于“低代码开发”的话题&#xff0c;简单的谈了些自己的看法&#xff0c;也看了一些朋友们各抒己见的好文章&#xff0c;今天想结合我们实际使用的开发平台和大家再做些探讨。 在平台的简介中首先提出了这个大家一定很关心的问题&#xff1a; 一、“为什么使用低代…...

嘉兴丝绸大厦做网站的公司/seo优化网站推广

最近工作电脑换成了64位的win7系统&#xff0c;之前个人电脑上安装的jdk和Eclipse都是32位的。而新的工作电脑上安装的JDK是64位的&#xff0c;因为原来的Eclipse自己安装了很多的插件和个性化配置&#xff0c;不想重新安装64位的Eclipse&#xff0c;所以想在64位的win7系统上继…...

wordpress如何添加模板文件夹/正规电商平台有哪些

到目前为止&#xff0c;你只是获取了被Java运行时系统抛出的异常。然而&#xff0c;程序可以用throw语句抛出明确的异常。Throw语句的通常形式如下&#xff1a;throw ThrowableInstance;这里&#xff0c;ThrowableInstance一定是Throwable类类型或Throwable子类类型的一个对象。…...

中国最著名网站建设公司/网站推广的100种方法

一、成员内部类&#xff1a; 成员内部类是创建在一个外部类内部的类。创建时必须通过外部类实例创建。例如 OuterClass outer new OuterClass();//创建内部类 OuterClass.InnerClass inner outer.new InnerClass();//利用外部类创建成员内部类成员内部类可以用public prote…...

合肥比较好的网站建设公司/西安优化seo

JAVA学习心得-----关于数组以及运用数组自定义队列 数组&#xff1a; 1.储存规定长度并且需要存入数据为相同类型。 2.格式为 数据类型[] 数组名 new 数据类型[]{内容}; 例如&#xff1a; 整形数组 int[] S new int[]{1,2,3}; 字符串数组 String[] S new String[]{“a”,“…...

网站开发在线课程/怎么自己做一个小程序

BERT模型自发布至今已整整两年了&#xff0c;但是其余热仍未消减。从一经问世的轰动&#xff0c;简单应用/微调便可达到某个领域或者任务的SOTA效果&#xff1b;到如今的各种『被吊打』&#xff0c;BERT巨人肩膀上的新宠大致可以分为以下这么几类&#xff1a;BERT &amp;amp…...

长沙新媒体运营公司/郑州网站seo优化

1. 数字图像类型 1.1 二值图像 概念: 二值图像是指每个像素值为О或为1的数字图像&#xff0c; 一般表示为黑白两色,如图所示。应用场景 由于只有两种颜色,只能表示简单的前景和背景, 二值图像一般不用来表示自然图像;但因其易于运算, 多用于图像处理过程后期的图像表示, 如…...