C#编程中容易对Equals方法误解的几个地方

作者:小菜 更新时间:2025-03-16 点击数:
简介:很多C#的教材都会强调对象相等的概念。

我们都知道,在C#的世界里存在两种等同性。

一种是逻辑等同性:如果两个对象在逻辑上代表同样的值,则称他们具有逻辑等同性。

另一

【菜科解读】

很多C#的教材都会强调对象相等的概念。

我们都知道,在C#的世界里存在两种等同性。

一种是逻辑等同性:如果两个对象在逻辑上代表同样的值,则称他们具有逻辑等同性。

另一种是引用等同性:如果两个引用指向同一个对象实例,则称他们具有引用等同性。

众所周知,Object类型有一个名为Equals的实例方法可以用来确定两个对象是否相等。

Object的Equals的默认实现比较的是两个对象的引用等同性。

而Object的派生类ValueTpye重写了Equals方法,它比较的是两个对象的逻辑等同性。

也就是说,在C#里,引用类型的默认Equals版本关注的是引用等同性,而值类型关注的是逻辑等同性。

当然,这并不总能满足我们的要求。

所以每当我们更在意引用类型的逻辑等同性的时候,我们就应该重写Equals方法。

重写引用类型的Equals方法以改变其默认的比较方式的一个著名例子是String类。

当我们写出“string1.Equals(string2)”这样的代码时,我们比较的不是string1和string2这两个引用所指向的是否为同一个实例(引用等同性),而是比较string1与string2所包含的字符序列是否相同(逻辑等同性)。

误解一:Equals方法和operator==具有相同的默认行为。

对于引用类型,如果没有为它重载==操作符,且其父类型也没有重写Equals方法,则这个引用类型Equals方法和operator==具有相同的默认行为,即它们比较的都是对象的引用等同性。

然而对于值类型来说,就完全不是这么回事了!因为如果你没有为自定义值类型重载operator==的话,就不能写这样的代码“myStruct1 == myStruct2”,否则会得到一个编译错误,原因是值类型没有相等操作符重载的默认实现。

误解二:自定义类的Equals的方法默认实现将自动调用operator==方法,或operator==方法的默认实现将自动调用Equals方法。

经常听到有人说某某类型是引用类型,所以它的Equals方法的默认实现将自动调用operator==方法。

这种说法完全是没有道理的。

正如上文所说的,引用类型Equals方法的默认实现来自Object,而值类型的默认实现来自TypeValue,就算他们会使用==操作符,使用的也是Object或TypeValue的重载版本。

原则上来说,只要我们没有重写一个类的Equals方法,那么它就会继承其父类的实现,而父类是没有机会使用子类型的操作符重载的。

同样,只要我们没有在一个类的==操作符重载中调用Equals方法,它是不会自动调用的。

误解三:值类型的默认Equals实现是对两个对象进行逐位比较的。

有些人认为值类型的Equals默认实现就是通过比较两个对象在内存中的位表示,即如果所有的二进制位都相等,则说明这两个对象“等同”。

这是不准确的。

因为其实值类型的Equals默认实现是对值类型的每个字段都调用该字段类型的Equals方法,如果所有字段的Equals方法都返回true,则他们才可能相等。

来看一个例子:class MyClass { public override bool Equals(object obj) { Console.WriteLine("MyClass的Equals方法被调用了。

"); return true; } } struct MyStruct { public MyClass Filed; } class Program { static void Main(string[] args) { MyStruct a; MyStruct b; a.Filed = new MyClass(); b.Filed = new MyClass(); Console.WriteLine(a.Equals(b)); } }很显然,a和b拥有完全不同的二进制位表示。

但是最终打印的结果是: MyClass的Equals方法被调用了。

True 这说明值类型的默认实现是通过调用字段的Equals方法来确定两个对象是否相等,而不是通过比较他们的二进制位是否一致来确定的。

误解四:Equals是非常基本、非常常用的方法,所以其默认的实现不存在性能问题。

对于引用类型,Equals的默认实现很简单,仅仅需要判断两个引用是不是同一种类型、两个引用指向的是不是同一块内存就可以了。

所以其性能也没有问题。

但是对于值类型,Equals的任务就没有这么简单了。

它需要对两个对象的所有字段都做出比较,即逐字段调用字段类型的Equals。

由于在ValueType(值类型Equals方法默认实现的位置)中,不可能知道它所有的子类型都包含哪些字段,所以为了调用子类型字段的Equals方法,ValueType的Equals就需要使用反射技术。

您可能已经看出来了,反射并不是一种性能友好的技术,所以值类型的Equals方法算不上高效。

这也正是为什么微软推荐我们为自定义值类型重写Equals方法的原因。

编程,中容,易对,Equals,方法,误解,的,几个,地方,

西门子plc编程根据要求写?学习SCL语言的基本语法规则

SCL:Structured Control Language,结构化控制语言。

SCL是一种类似于计算机高级语言的编程方式,只是这种语言编写的程序,可以在PLC中运行。

如果学过C语言或者VB语言,就会很容易上手SCL。

当然没有基础依然可以从零开始学习。

在PLC中有了SCL这种编程语言,就可以方便地把计算机高级语言,编写的算法移植到PLC中。

西门子以下系列的PLC都支持SCL语言编程:S7-300S7-400S7-1200S7-1500WinAC SCL能实现复杂的运算功能,特别是有大量数据要处理的时候。

相对于梯形图SCL在运算、函数、过程优化方面有天然的优势。

在博途软件中已经集成SCL语言包,可以直接使用SCL进行进行编程。

在传统的STEP7 中需要单独的安装 S7-SCL 软件包。

因为SCL是一种高级编程语言,所以就包含表达式、运算符、程序控制语句等语言元素。

1、表达式 SCL中有三种表达式:算术表达式关系表达式逻辑表达式 一个完整的表达式是由操作数和与之搭配的操作符组成。

通过表达式的特定顺序进行运算,并返回一个值。

操作数:常数、变量、函数调用(在PLC编程中可以理解为地址)。

操作符: 、- 、、/ (加减乘除),and、or、not(与或非)等。

操作符有时也叫运算符,SCL支持的运算符有算术运算符、比较运算符、逻辑运算符、赋值运算符。

算术运算符:主要是我们常用的加( )、减(-)、乘()、除(/),以及数学上常用的取正、取负、求余数、整除、求余(%)。

比较运算符:用于数值的比较,主要有大于、小于、等于、不等于。

逻辑运算符:用于布尔型值的运算,常用的逻辑运算符除了与、或、非之外,还有异或。

赋值运算符:通过赋值运算,可以将一个表达式的值赋给一个变量。

赋值运算符左侧为变量,右侧为表达式的值。

赋值运算的计算按照从右到左的顺序。

1.1、算术表达式 算术运算符: 、-、、/、DIV、MOD、。

算术表达式通常由常量、变量、函数、圆括号、运算符等组成。

算术表达式也叫数学表达式,是三种表达式中最简单的,几乎可以等同于数学运算。

西门子PLC的算术表达式,支持各种数据类型。

一个算术表达式的两个操作数,如果分别属于不同的数据类型,依然可以运算。

运算结果的数据类型,如下图所示: 虽然不同的数据类型可以算术运算,还是建议大家先进行数据格式转换,然后进行运算。

防止出现运算后,不知道数据格式,导致数据错误。

1.2、关系表达式 关系运算符:=、==、。

关系表达式是利用关系运算符,将两个操作数或数据类型进行比较,然后得到一个布尔值(BOOL)型的逻辑结果。

如果比较结果为真,菜叶说说,则结果为1(TRUE),否则为0 (FALSE)。

所以关系表达式的值只能是逻辑值真或假(1或者0)。

关系表达式有时候也称作比较表达式。

西门子PLC的关系表达式,支持各种数据类型,结果的数据类型只能是布尔型。

以下数据类型,只能比较相同类型的变量: TIME日期和时间UDT 1.3、逻辑表达式 逻辑运算符:AND(&)、OR、NOT、XOR。

西门子PLC的逻辑表达式,支持各种数据类型。

但是在运算中会出现两种情况。

一是,两个操作数都是布尔(BOOL)数据类型,则逻辑运算的结果也为布尔数据类型。

另一种情况,如果两个操作数中至少有一个是位序列,则结果也为位序列。

结果由最高操作数的数据类型决定。

例如,当两个操作数分别是字节(Byte) 类型和字(Word)类型时,结果为字(Word)类型。

逻辑表达式中一个操作数为布尔(BOOL)类型而另一个为位序列时,必须先将 布尔(BOOL)类型的操作数显式转换为位序列类型。

#p#分页标题#e# 位序列:一组由0和1组成的序列。

auto是深入解析其在编程中的多重含义

简介:在编程中,"auto"是一个多义词,通常用于提高代码的灵活性和可读性。

在C++等编程语言中,"auto"可以帮助程序员高效地管理数据类型和变量声明。

然而,除了在编程语言中外,"auto"在其他编程工具和开发环境中也有不同的应用。

本篇文章将深入解析"auto"在编程中的多重含义,并为您提供实用操作建议。

工具原料:系统版本:Windows 11, macOS Monterey品牌型号:Dell XPS 13 (2022), MacBook Pro 14-inch (2023)软件版本:Visual Studio 2022, Xcode 14一、"auto"在C++编程中的应用1、在C++11标准中引入的类型推导功能使得"auto"关键字极大地简化了代码编写。

对于那些希望减少重复代码和明显类型声明的开发者而言,"auto"是一种便捷且安全的选择。

例如,您可以通过"auto"让编译器自行推断变量的数据类型,从而提高开发效率和代码可读性。

2、实践中,许多C++开发者在使用STL(标准模板库)时会应用"auto"。

比如,当使用迭代器遍历容器时,使用"auto"进行类型声明可以避免手动指定复杂的迭代器类型。

这不仅让代码更简洁,而且减少了因手动类型错误导致的bug。

二、"auto"在Python中的应用1、虽然Python不像C++那样需要显式的类型声明,但"auto"的理念体现在它的动态类型特性中。

Python变量无需在声明时绑定类型,这种灵活性使开发者在处理不同数据类型时更加从容。

2、在数据科学和机器学习领域,Python中的自动类型推断可以使开发者更加专注于算法本身,而不必过多担心数据类型的转换。

这为快速原型设计和迭代提供了便利。

三、"auto"配置和自动化工具1、在现代软件开发中,"auto"不仅局限于编程语言,更延伸到自动化工具和配置管理中。

以CI/CD(持续集成/持续交付)工具如Jenkins为例,它能够通过"auto build"配置,在每次代码变更后自动化地触发构建流程,以保证软件的持续可用性。

2、另外,在前端开发中,工具如Webpack提供了自动打包和热加载的功能,显著提高开发效率和提升开发者体验。

拓展知识:1、了解"auto"在不同编程环境中的角色有助于更灵活地使用这项技术。

比如,在Rust编程语言中,虽然没有"auto"关键字,但编译器同样支持类型推断,这类机制在许多现代编程语言中均得到了应用。

2、此外,"auto"的理念在人工智能和自动化测试领域也开始发挥作用。

机器学习模型的"自动调参"功能,自动优化测试用例等技术持续推动着行业效率的提升。

总结:通过本篇文章,我们深入探讨了"auto"在多种编程情境中的含义及其应用价值。

从C++类型推断到自动化工具的配置,"auto"展现了其提升开发效率的潜力。

希望本篇文章能够为开发者在日常编码中提供丰富的参考和实用建议,从而更高效地利用编程工具。

加入收藏
               

C#编程中容易对Equals方法误解的几个地方

点击下载文档

格式为doc格式

  • 账号登录
社交账号登录