二、C#数据类型

本文是网页版《C# 12.0 本质论》第二章解读。欲完整跟踪本系列文章,请关注并订阅我的Essential C# 12.0解读专栏。

前言

数据类型(Data Type)是一个很恼人的话题。

似乎根本没必要对数据类型进行展开讲解,因为人人都懂。

但是,数据类型本身又确实比较复杂,不仅涉及到值类型和引用类型,也涉及到内置类型和自定义类型,更涉及到C#类型、.NET类型、通用类型系统CTS、通用语言规范CLS、.NET standard等很多概念。

本文就力争通过示例,把这些概念理清楚。

引例

请看下面程序示例:

namespace DataTypes
{internal class Program{static void Main(){DataTypes.Program pro = new DataTypes.Program();string name = "Julian Zhang";int age = 58;Console.WriteLine($"My name is {name}, and I'm {age} years old.");}}
}

Main中出现了string、int和DataTypes.Program三种数据类型。

我们都知道,C#语法是区分大小写的,比如你将Program的字符P改成小写(DataTypes.program),编译就无法通过,会出现如下报警:

Error CS0234 The type or namespace name ‘program’ does not exist in the namespace ‘DataTypes’ (are you missing an assembly reference?)

类似地,如果将int改成Int也会报错:

Error CS0246 The type or namespace name ‘Int’ could not be found (are you missing a using directive or an assembly reference?)

但如果将string的首字母改成大写,也就是改成String,系统却不会报错,运行也正常。

为什么会这样?难道C#为字符串类型提供了两个关键字,分别为string和String?但我们到微软官网查一下C#关键字,发现只有string,并没有首字符大写的String,说明这个猜想是错误的。

在说明这个问题之前,我们需要先将话题扯远一些。下面请听我慢慢道来。

CTS与CLS

中间语言的价值

上一篇开始部分,我们引用了Serge Lidin的名著《Expert .NET 2.0 IL Assembler》中的一张图,展示了托管应用程序的生成与执行模型。在那种图中,C#源代码(Source Code)经C#编译器(Managed Compiler)编译链接以后,生成了程序集(Managed Module)文件。程序集文件中其实并不包含CPU可以直接执行的本机代码(Native Code),Managed Module中只有文件头、Metadata和IL代码。

我们可以把IL看作是另外一种高级语言,IL代码还必须再经过IL编译器编译,变成成本机代码以后,才能被CPU执行。

那么,微软为什么要搞一个IL作为二传手?为什么不像C/C++一样直接编译成本机代码?

IL是Intermediate Language的简称,也就是中间语言。使用中间语言过渡有很多优点,而这也恰恰是.NET平台的本质所在。下面我们通过一个故事来说明其中的道理。

我们知道,C语言非常流行,无论在Windows平台、Linux平台或MacOS系统,都有不错的C语言编译器支持。

假设张三想开发一种新的编程语言,假设就叫CA语言吧。如果CA语言编译器不是将CA源程序编译成本机代码,而是编译成C语言源程序,那么我们就可以使用CA语言来写C程序了。此后,只要我们再用不同平台的C编译器编译一遍,该程序就可以运行在对应平台上。

至于为什么不直接使用C而要发明CA,可能是因为C的语法太复杂,或者C本身不够安全,或者是其他任何原因,总之原理上讲,是可以这样做的。

另外,正因为CA语言会被编译成C,所以CA语言根本没必要再搞一套数据类型,直接使用C语言的数据类型即可,比如CA完全可以将如下C类型直接拿来使用:

  • char:‌用于表示字符或小整数,‌占用1字节。‌
  • short:‌用于表示短整数,‌占用2字节。‌
  • int:‌用于表示整数,‌通常为4字节。‌
  • long:‌用于表示长整数,‌通常为4或8字节。‌
  • long long:‌用于表示更长的整数,‌占用8字节。‌
  • float:‌用于表示单精度浮点数,‌占用4字节。‌
  • double:‌用于表示双精度浮点数,‌占用8字节。‌
  • long double:‌用于表示更高精度的浮点数,‌通常为8或16字节。‌
  • bool:‌用于表示真(true)或假(false)的值。‌
  • 指针和引用类型
  • 等等…

至此,虽然通过CA来写C程序的理由还基本说得过去,但总感觉依旧有些牵强,似乎必要性也不是很高。

接下来,李四受到张三启发,也考虑发明另外一种编程语言CB,并决定CB的语法主要参考Visual Basic,但CB也是被编译成C源代码,然后再用C编译成本机代码,且CB也直接使用C语言类型。

后来王五、赵六又分别发明了CC和CD语言,也是以C语言为底层,且直接使用C的数据类型。

此时,CA、CB、CC、CD这四种编程语言之间就出现了一个很好特性:他们都直接使用C语言作为底层语言,所以他们的函数调用约定完全相同,程序之间的互相调用无需考虑从左向右压栈还是从右向左压栈,也无需考虑由调用者清理栈参数还是由被调用函数清理栈参数,更重要的是,大家最后生成的都是C语言代码,都使用C语言的类型,于是互相调用时根本无需考虑类型转换,这为不同语言间共享代码提供了极大便利。

于是,这种模型的好处渐渐凸显:不仅可以方便地编译成不同平台程序,而且还可以互相调用对方代码。也就是说,无论程序员喜欢CA语法还是CB语法,最终的程序并不存在差异。

所以,这种使用C作为中间语言的平台结构,为跨平台应用开发、代码相互代码调用及数据类型统一奠定了坚实基础。

回到我们现实的C#和IL语言,C#就类似于上述的CA - CD,而IL就类似于上述的C语言。

如今,在.NET大厦,不仅入驻了C#,还入驻了F#, VB.NET, IronPython, C/CLI等众多语言,他们都可以类比成上述故事中的CA - CD语言,只不过底层不是C,而是IL语言。

那么,微软为什么没有直接使用C作为中间语言,而是重新发明轮子,又搞了一个IL语言?

中间语言的设计原则

作为中间语言,最好具备如下特点:

  • 原子性:只包含最基本的指令,比如加减乘除、读写存储器、子程序调用和跳转分支,而不要有太复杂的指令,确保指令条数有限;
  • 指令代码短:指令代码尽可能短,这样编译出来的中间代码就短,再次编译时就快,且少占内存和硬盘空间;
  • 最好和CPU硬件无关,这样才便于在不同平台使用,所以最好不要直接使用特定与CPU的寄存器;

正因为基于以上考虑,微软发现现有的编程语言均难堪此任,所以才搞了IL语言(微软最初称其为MSIL,后来ECMA称其为CIL,C#程序员则一般直接称其IL)。

MSIL实现了以上原则,指令数量极少,非常容易学习。为了减少指令数量,并确保指令字节短且CPU硬件无关,IL不再使用寄存器,所有操作均通过栈进行,所以绝大多数指令基本只有一个字节操作码。

可以说,IL语言的发明,为.NET平台建设奠定了第一块基石。

IL类型

既然IL语言作为其他.NET语言的底层,那么IL语言就应该定义自己的类型系统,比如int, string,class, struct等等。
IL语言设计之初就将其规划成全面支持面向对象的结构,所以虽然其原子性与CPU指令类似,但本身已完全支持面向对象编程理念。其类型系统设计也就直接提供了面向对象支持。下面举例几个IL直接定义好的类型:

string
int16
int32
int64
float32
float64
object

但是,此时微软意识到,要想吸引全球程序员都愿意基于IL开发新的编程语言,就有必要对IL进一步标准化,比如:

IL语言语法
IL数据类型系统
IL被编译后的文件格式
IL被编译后的文件如何运行?
IL需提供哪些标准库?
IL标准库需提供哪些基本函数?

于是,微软开始着手制定一系列标准,并成功将这些标准推广成国际标准(ECMA/ISO)。微软将这一些列标准统称为.NET平台,可以说.NET平台是微软对IL的更高层次抽象,而IL则成为.NET平台的一部分,或者说,.NET平台包含IL语言。而ECMA/ISO则将.NET平台又改名为CLI(Common Language Infrastructure)。

这种抽象过程中,标准制定者发现,有必要进一步将IL类型系统区分成CTS和CLS,于是IL类型系统就成了仅供IL语言使用的类型,而以前直接使用IL类型的高级语言,则改成直接使用CTS类型。有关CLS我们稍后再说,首先接介绍一下CTS。

CTS

ECMA将CLI中定义的所有类型的集合定义为CTS,全称是Common Type System。其中的Common已经很容易理解,也就是可供所有基于CLI平台的高级语言共同使用的类型系统。

事实上,IL语言实现了CTS的所有类型,只不过为防止以后万一需要将IL和CTS分开,所以单独定义了CTS,并且如此区分以后,ECMA规定,任何基于CLI开发的高级语言,都可以直接使用CTS类型名。

下面截图是ECMA-335中列举CLI内置类型:
在这里插入图片描述
最左侧列是IL类型名,红框中是对应的CTS类型名,虽然大小写不同,有些名称也不同,还有CTS使用了名称空间并以半角点将名称空间和类型名进行了分隔,但同行中两个名称的含义是完全等同的。

基于以上解释,我们知道了如下基本道理:

  1. 因为任何基于CLI的高级语言都可以直接使用其支持的CTS名称,而VB.NET及C#都是基于CLI的高级语言,所以C#中可以直接使用System.String,也可以直接使用System.Int32,但不可以直接使用System.Int,因为它不存在。
  2. 因为我们的C#程序使用了.NET 8.0框架,默认项目文件中ImplicitUsing选项是enable的,也就是相当于已经有了using System,所以System.String可以被简写为String,同理System.Int32也可以被简写成Int32;但如果将这个enable改为disable,那么就必须加上System名称空间。

至此,我们已经知道,C#中可以使用String并不是C#语法的原因,而是CLI标准的原因,在VB.NET中也同样可以使用CLI类型。

那么,全小写的string或int又是怎么回事儿呢?这当然是C#编译器设计者的决定了。这些语言发明者觉得,System.String或System.Int32写起来太长,不方便,于是就规定了使用string作为System.String的别名,使用int作为System.Int32的别名。于是,string和int就成了C#语言的关键字。

CLS

既然CLI被设计为底层框架,那么CLI的CTS系统定义的类型就必须足够丰富。可以想象一下,如果CTS中只有两种类型,比如:

  • 十六位的整型:System.Int16
  • 32位浮点数:System.Single

我相信任何人都不会愿意基于CLI开发上级高级语言,因为数据类型太少了,根本不够用!

所以,CLI为了兼顾各种应用场景需求,在CTS设计上包含了非常丰富的数据类型。

不过,数据类型如果太多,高级语言的设计就会比较复杂,而且最重要的是众口难调。比如CA语言设计者认为,整型只要有8位~64位有符号型就够了,但CB设计者认为无符号整数其实很有用,有助于减少空间占用。这种冲突会对相互调用造成问题,比如CB调用CA返回了一个十六位的数据EF05h,因为CA只使用有符号整数,所以CA返回的EF05h其实想代表负数-4347;但CB支持16位无符号数,且将这个返回值赋值给了一个无符号变量x,那么x将被解释成正数61189。

类似的问题要如何协调?

于是,CLI在CTS的基础上,又抽象出一个新概念叫CLS(Common Luanguage Specification)。
CLS规定了所有高级语言都必须支持的一组数据类型,CLS是CTS的子集,只要大家都确保符合CLS,那么互相调用就不会发生问题。

在这里插入图片描述

上图举例了三种基于CTS的编程语言,分别是N#(某种假想的语言)、C#和VB,其中C#和VB是符合CLS的语言,但N#是不符合CLS的语言,这张图包含了以下三层含义:

  • VB和C#语言都提供了对CLS的支持,意思是说VB和C#都对CLS规定了类型提供了全部实现;
  • N#是不符合CLS的语言,所以至少有一种CLS类型未被N#实现,所以即便声称符合CLS的程序,被N#调用也可能出现问题;
  • 并非VB或C#编写的程序自动符合CLS,而是说如果某程序声称符合CLS,那么一定可以被VB或C#安全调用;

至此,我们已经弄清了CLS。之前我们提到的CLI类型表的第二列(CLS Type)的含义也就不言自明了:所有CLS支持的类型就标记为Yes,否则就标记为No。

那么,C#语言支持的数据类型中,哪些是符合CLS的呢?借用一张网上找到的图来说明:

在这里插入图片描述
也就是说,如果一个C#应用程序对外提供的接口成员(公共方法的参数、返回值以及自定义类型中所有可被外部访问的成员)如果均使用了上表中CLS标记为“是”的类型,那么这个程序就是满足CLS规范的程序,其他基于CLI的高级语言可以放心调用。否则就是CLS不兼容,需要格外小心使用。

以上,我们完成了CLI数据类型、C#数据类型、IL数据类型、CTS和CLS的体系介绍。

接下来我们先简单说一下值类型和引用类型。

值类型和引用类型

CLI规定,从存储模式角度,数据类型可以分为值类型和引用类型两类,如下图所示:

在这里插入图片描述
一般教科书会说,值类型保存在栈空间,引用类型保存在堆空间。不过这种说法比较模棱两可,并不严密。

严格一点说,无论值类型变量还是引用类型变量都保存在栈空间中。变量其实就是一个栈空间的地址。

如果该变量是值类型,那么该变量对应的栈空间中就会直接保存这个数值。比如int x = 10定义了一个值类型变量x,那么x其实就是内存栈空间一个内存地址,它是编译迁建由编译器和链接器确定的,假设是0x00101010h,那么 x = 10 这条指令就会将 0x00101010h写上数据10。如果后续又有指令 x = 20,那么会立即将0x00101010h改为20。

如果一个变量是引用类型,比如Person person = new Person(),那么,同值类型变量一样,也是在编译期间编译器和链接器就会为person变量生成一个栈空间地址,比如0x00101018h。程序运行到new指令时,CLR会首先到堆空间申请一块可以容纳Person类型的堆空间,然后将堆空间的首地址存入0x00101018h地址的内存中,接下来再调用Person构造函数堆堆空间这个对象进行初始化,也就是在初始化修改person实例数据时,person变量中一直是最初申请的地址,并不会发生变化。无论之后该对象的字段发生什么变化,person变量中的内容都会保持不变。

以后机会合适时,我会通过具体实例对此做进一步说明。暂时先了解到这个程度即可。

程序的执行方式

自高级编程语言产生之时开始,就存在解释方式和编译方式两种程序执行模式。

典型的解释型程序语言有BASIC和JavaScript,他们的源程序无需经过编译,而是在运行期间依赖于一个被称为解释器的程序来实现运行。解释器的作用就是一句源代码一句源代码地翻译,每翻译一句,CPU就执行一句。

编译型语言,如C/C++/C#则与解释型语言不同,他们运行前需先经过编译步骤,将源代码编译成可执行代码。当然,如前所述,C#编译后的代码与C/C++又有所不同,C#源文件最终被编译成了程序集,里面除了文件头,就只有metadata和IL代码,仍不能直接被CPU运行,还需要再次经过IL编译器编译。

之前我们假设C语言作为中间语言的CA - CD语言,首先会被编译成C语言源代码,然后再用C编译器将其编译成本机代码。但IL代码文件的执行方式与我们假想的C作为中间语言不同,IL代码虽然不能直接被CPU执行,但并不需要再次被编译成本机代码,而是可以直接运行。只不过运行的时候需要一个类似于BASIC解释器的软件帮助,这个软件由.NET平台提供,称为CLR。每次IL代码文件被加载到内存时,CLR总是会被操作系统同时加载,然后CLR中的JIT编译器会实时将IL编译成本机代码,然后再交给CPU执行。

正因为有了CLR的即时编译能力,所以才使.NET托管程序真正具备了跨平台特性:同一套代码,可以在任何安装有CLR的环境下直接运行,也就是可以将一次性编译后的dll文件同时拷贝到Windows、Linux和MacOS,都可以使用dotnet命令直接运行。

至此,我们才算基本说清楚了.NET与C#的关系:

  • .NET是微软对基于IL语言的底层一组服务的概括性抽象,.NET符合ECMA-335规定的CLI标准,但又对CLI有所扩展;
  • CLR可以看成是微软针对CLI中VES(Virtual Executing System)即虚拟执行系统的实现,有些微软文档也称其为EE(Executing Engine);
  • IL是.NET平台或者说是CLI的组成部分,但C#等高级语言与CLI或.NET之间不存在包含关系,建立在.NET平台基础上的高级语言,是遵从CLI标准的高级语言具体实现。
  • 只有IL语言完整实现了CTS,所有其他高级语言都未实现CTS的全部功能,也就是说,只有IL语言才是.NET平台的功能霸主。

内置类型

如果我们自己定义了一个类型,假设是MyNameSpace.Employee,单独编译成了一个类库MyType.dll。如果我们需要在自己的应用程序中调用,首先必须在项目中加入对MyType.dll的引用,然后才能在我们的代码中使用这个Employee类。

但是,你无需引用任何dll,直接就可以在C#程序中使用int, string等类型。

无需提供任何显式引用,编译器天生就支持的类型,称为内置类型。对于C#,所有C#关键字类型都是内置类型。

内置类型并非空穴来风,内置类型也是预定义类型,只不过是.NET平台帮我们预定义好的类型而已。

比如我们在int 类型上F12,会发现其定义文件前三行内容如下:

#region Assembly System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\8.0.3\ref\net8.0\System.Runtime.dll
#endregion

也就是说,int是定义在System.Runtime.dll文件中的,只不过C#编译器自动认识这个类型,能自动找到合适的定义入口而已。

与此类似,如果查看string类型,会发现,它其实定义在:

System.Private.CoreLib.dll中。

类型的内涵与外延

当我们使用自定义类型时,比如使用如下语句:

MyNameSpace.Employee emp = new MyNameSpace.Employee();

首先,类型决定了emp对象的内存布局:共占多少字节?每个字节的二进制位含义?各字节的前后关系,等等;

其次,类型决定了可以在该类型上施加哪些操作。比如只有该类型定义了SayHello()方法,你才能在emp变量上使用SayHello,不能使用未在该类型中定义的方法。

对于可施加的操作,除了方法,还有操作符重载、类型转换等。比如查一下Int32类型的源代码,你会发现,看似最简单的int类型,其源文件竟有1460多行。int型之所以可以进行加减乘除运算,是因为 源代码中定义了这些操作,比如:

加法操作(+):

        /// <inheritdoc cref="IAdditionOperators{TSelf, TOther, TResult}.op_Addition(TSelf, TOther)" />static int IAdditionOperators<int, int, int>.operator +(int left, int right) => left + right;

自增1操作(++):

        /// <inheritdoc cref="IIncrementOperators{TSelf}.op_Increment(TSelf)" />static int IIncrementOperators<int>.operator ++(int value) => ++value;

二进制左移位操作(<<):

        /// <inheritdoc cref="IShiftOperators{TSelf, TOther, TResult}.op_LeftShift(TSelf, TOther)" />static int IShiftOperators<int, int, int>.operator <<(int value, int shiftAmount) => value << shiftAmount;

转换成字符串操作(string.TryParse()):

        /// <inheritdoc cref="IParsable{TSelf}.TryParse(string?, IFormatProvider?, out TSelf)" />public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out int result) => TryParse(s, NumberStyles.Integer, provider, out result);

因此我们说,类型定义的目的,不仅为了告诉编译器该如何为类型分配内存,如何初始化类型,如何在编译期检查是否存在非法操作,而且还能告诉CLR,在运行时如何检查操作是否合法。

数字类型

这部分内容基本直接引用了原书。我们每天都在和数字类型打交道,所以即便简单,也应引起足够重视。

整型

整型总计有十种,没什么好说的,仅列出表格:
在这里插入图片描述

浮点型

浮点型有两种,一种是32位的float,另一种是64位的double。
在这里插入图片描述
首先需要注意,浮点型是非精确数据,存在精度损失,所以不要用浮点型进行全等比较。比如无论是float还是double,都不能精确表达0.1,因为浮点数使用的是二进制指数格式存储数据,十进制的0.1转换成二进制是无限位。

浮点数表达方式比较复杂,权威标准是IEEE754或ISO IEC 60559-2020。曾经,我研究得很明白,但过一段时间以后,还是会再次模糊。不过,依旧建议大家有时间时彻底搞懂一次,然后,即便忘记了细节,也不会再对浮点数感觉恐惧。

下面两张图,代表了浮点数最核心的要点:

在这里插入图片描述
在这里插入图片描述

decimal

注意: decimal外观很像浮点数,比如123.4567M就是一个decimal类型,但decimal的二进制表示与float截然不同,它不是使用二进制转换得到的,而是直接用十进制数据位和指数位做存储。
所以,decimal类型可以精确表示十进制数据,比如0.1M就是精确的十进制0.1,无丝毫含糊。
前文提到,不要对浮点数比较全等;但decimal可以比较全等。

在这里插入图片描述

待续

类型系统本身就是一个非常复杂的话题,比如浮点数在内存中是如何存储的?Unicode到底是怎么回事?类和实例在内存中的具体存储方式?CLR类型数据结构与CTS之间的关系等等。因为此话题涉及的领域众多,所以本文只能分阶段续写,请留意日后更新。

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

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

相关文章

grafana大坑,es找不到时间戳 | No date field named timestamp found

grafana大坑&#xff0c;es找不到时间戳。最近我这边的es重新装了一遍&#xff0c;结果发现grafana连不上elasticsearch了&#xff08;以下简称es&#xff09;&#xff0c;排查问题查了好久一直以为是es没有装成功或者两边的版本不兼容&#xff0c;最后才发现是数值类型问题 一…

浅聊 Three.js 屏幕空间反射SSR-SSRShader

浅聊 Three.js 屏幕空间反射SSR(2)-SSRShader 前置基础 渲染管线中的相机和屏幕示意图 -Z (相机朝向的方向)||| -------------- <- 屏幕/投影平面| | || | || | (f) | <- 焦距| | ||…

【BUG】已解决:error: legacy - install - failure

error: legacy - install - failure 目录 error: legacy - install - failure 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&…

51单片机14(独立按键实验)

一、按键介绍 1、按键是一种电子开关&#xff0c;使用的时候&#xff0c;只要轻轻的按下我们的这个按钮&#xff0c;按钮就可以使这个开关导通。 2、当松开这个手的时候&#xff0c;我们的这个开关&#xff0c;就断开开发板上使用的这个按键&#xff0c;它的内部结构&#xff…

免费分享:2021年度全国城乡划分代码(附下载方法)

《关于统计上划分城乡的规定》指出&#xff1a;“本规定作为统计上划分城乡的依据&#xff0c;不改变现有的行政区划、隶属关系、管理权限和机构编制&#xff0c;以及土地规划、城乡规划等有关规定”。统计用区划代码和城乡划分代码用于统计工作&#xff0c;需要在其他工作中使…

回溯题目的套路总结

前言 昨天写完了LeeCode的7&#xff0c;8道回溯算法的题目&#xff0c;写一下总结&#xff0c;这类题目的共同特点就是暴力搜索问题&#xff0c;排列组合或者递归&#xff0c;枚举出所有可能的答案&#xff0c;思路很简单&#xff0c;实现起来的套路也很通用&#xff0c;一…

java题目之抽奖以及优化方式

public class Main9 {public static void main(String[] args) {int[]arr{ 2,588,888,1000,10000};int [] newArrnew int[arr.length];//3.抽奖Random rnew Random();//因为有5个奖项,所以这里循环五次for (int i 0; i <5 ; ) {//获取随机索引int randomIndexr.nextInt(arr…

前端-模拟请求数据mook第三方插件 json-server的使用

大纲 第一步下载第二配置mook的数据源第三配置启动命令第四运行模拟服务第五测试接口如果要进行更复杂的操作 第一步下载 npm install json-server -D"devDependencies": {"json-server": "^1.0.0-beta.1"}第二配置mook的数据源 在项目的根目录…

图纸为什么需要加密?2024超好用的图纸加密软件推荐

图纸通常包含产品的设计细节、规格和技术信息&#xff0c;这些都是公司的核心知识产权。加密可以防止未经授权的访问和复制&#xff0c;避免知识产权被盗用或侵权。 图纸加密软件对于保护企业的知识产权和商业秘密至关重要&#xff0c;特别是在CAD&#xff08;计算机辅助设计&…

内网安全:各类密码的抓取

Mimikatz在线读取SAM文件 离线读取SAM文件 在线读取lsass进程 离线读取lsass进程 BrowserGhost浏览器密码抓取 Sharp-HackBrowserData浏览器密码抓取 SharpDecryptPwd数据库密码抓取 LaZagne各类密码的抓取 Windows其他类型抓NTLM Hash工具 sam文件和lsass进程就是Wind…

谷粒商城-商品上架

1.sku在es中的存储模型分析(spring整和es) es中所有数据存在内存中,内存产品贵,能节省就节省,只保存有用的信息 两种保存方法:(空间换时间,时间换空间): 我们选空间换时间 ES中放这些东西: "mappings": { "properties": { "skuId"…

【C++】deque以及优先级队列

容器适配器 deque的介绍deque的原理介绍 priority_queue的介绍与使用priority_queue的介绍priority_queue的使用constructor&#xff08;构造函数&#xff09;emptypushpoptopsize priority_queue的模拟实现 仿函数何为适配器容器适配器deque的缺陷选择deque作为适配器的理由ST…

使用element UI Cascader 级联选择器实现省/市/区选择

<template><div><label>位置</label><el-cascader:options"pcaTextArr"v-model"selectedOptions"change"handleChangeAddress":props"{expandTrigger: hover,multiple: true,checkStrictly: true,emitPath: fal…

mailcow搭建安装教程:如何搭建专属邮箱!

mailcow搭建安装教程怎么用&#xff1f;怎么有效搭建邮箱服务器&#xff1f; 随着电子邮件在工作和生活中的重要性日益增加&#xff0c;拥有一个专属的电子邮件服务器变得越来越有吸引力。AokSend将详细介绍如何通过mailcow搭建一个专属邮箱&#xff0c;为你提供全方位的邮件管…

看起来很炫酷的科技感登录页面模板HTML

代码下载地址&#xff1a; 炫酷科技感登录页面模板带动画 (bootstrapmb.com)https://www.bootstrapmb.com/item/11891

Mailspring搭建安装教程:打造个性邮件体验

Mailspring搭建安装教程步骤&#xff01;如何选择电子邮件服务商&#xff1f; Mailspring作为一款功能强大、界面友好的邮件客户端&#xff0c;成为了许多用户的首选。AokSend将为大家提供详细的Mailspring搭建安装教程&#xff0c;帮助您打造个性化的邮件体验。 Mailspring搭…

Mybatis<collection>实现一对多

时隔多年又用到这样的查询方式了,提前声明一下分页最后返回的数据会小于每页条数&#xff0c;废话不多说直接上代码&#xff01; Data public class PbcUserTargetTaskPageVO {ApiModelProperty("个人绩效指标id")private Long id;ApiModelProperty("月份"…

uniapp判断h5/微信小程序/app端+实战展示

文章目录 导文使用条件编译的基本语法常见的平台标识符示例实战展示使用场景举例注意事项 导文 这里是导文 当你在开发Uni-app时&#xff0c;需要根据不同的平台&#xff08;比如App端、H5端、微信小程序等&#xff09;来执行不同的代码逻辑&#xff0c;可以使用条件编译来实现…

使用Fiddler进行Android和IOS抓包

Android抓包 要使用Telerik Fiddler Classic捕获Android设备的网络流量&#xff0c;您需要执行以下步骤&#xff1a; 在Fiddler Classic上进行设置&#xff1a; 确保已安装并使用BouncyCastle作为证书生成器。较新的Android版本会拒绝有效期超过两年的证书&#xff0c;目前只…

微信小程序开发--点击圆圈小问号弹注解tip 点击其他区域关闭(组件 w-tip 弹框在小圆圈的 上下左右 可以自己控制 )

引言 在微信小程序开发中&#xff0c;实现用户交互的多样性是提升用户体验的关键之一。本文将详细介绍如何在微信小程序中实现点击圆圈小问号弹出注解&#xff08;Tip&#xff09;的功能。这种功能常见于帮助信息、提示说明等场景&#xff0c;能够为用户提供即时的帮助和反馈。…