C#基础操作符详解(下)
书接上文的基本操作符,下文介绍的是其他操作符:
4.2一元操作符:
只要有一个操作数跟在它后面就可以构成表达式,也叫单目操作符。
①&x和*x操作符(很少见有印象即可):
这两个操作符同样也需要在不安全的上下文中运行:&是取地址操作符。
简单错误:*pStu.错误:由于.为基本操作符优先级大于*所以是先进行pStu.的操作正确应该为:(*pStu).即加个括号。
②+、-、!、~四个一元操作符:
-运算符可造成内存溢出:
int a = int.MinValue;
int b =checked( -a);//原因在于int.MaxValue与int.MinValue绝对值不一样。
~求反操作符,对操作数转化为2进制,进行二进制的按位取反。
计算机取相反数的原理:先把该数转化为2进制再按位取反+1
!操作符只能用来操作布尔类型的数据,
③++x;--x运算符:单独使用时x++与++x没有区别。
4.3、强制类型转化操作符:(T)x,T表示某种数据类型。
类型转换:
①隐式(implicit)类型转换,常见的为以下三种情况:
*不丢失精度的转换:小字节数(存储空间)的数据类型向多字节(存储空间)的数据类型转换不会丢失精度,比如金鱼从鱼缸里放到游泳池里还是好好的。例如:
int x = int.MaxValue;
long y = x;
这就是在不丢失精度的情况下进行的隐式类型转换,具体哪些数据类型可向哪些无丢失精度类型转换见C#语言定义文档6.1.2:
隐式数值转换为:(原则为从小的向大的转)
l 从 sbyte 到 short、int、long、float、double 或 decimal。
l 从 byte 到 short、ushort、int、uint、long、ulong、float、double 或 decimal。
l 从 short 到 int、long、float、double 或 decimal。
l 从 ushort 到 int、uint、long、ulong、float、double 或 decimal。
l 从 int 到 long、float、double 或 decimal。
l 从 uint 到 long、ulong、float、double 或 decimal。
l 从 long 到 float、double 或 decimal。
l 从 ulong 到 float、double 或 decimal。
l 从 char 到 ushort、int、uint、long、ulong、float、double 或 decimal。
l 从 float 到 double。
从 int、uint、long 或 ulong 到 float 的转换以及从 long 或 ulong 到 double 的转换可能导致精度损失,但决不会影响数值大小。其他的隐式数值转换决不会丢失任何信息。
不存在向 char 类型的隐式转换,因此其他整型的值不会自动转换为 char 类型。
*子类向父类的转换;
例如定义三个互相继承的类:
class Animal { public void Eat() { Console.WriteLine("Eat"); } } class Human:Animal { public void Think() { Console.WriteLine("think"); } } class Teacher:Human { public void Teach() { Console.WriteLine("Teach"); }
在main函数中:
Teacher t = new Teacher();
Human h = t;//这种就是子类向父类隐式类型换
而h.只能访问Human类的成员,不能访问Teacher类的成员,因为引用变量只能访问它这个变量的类型它所具有的成员,注意是这个变量的类型是(Human)而不是这个变量引用的类型(Teacher)。(简单的比喻比如人的父类是猴子,但猴子的只能做猴子的行为而不能做人类的行为。)
*装箱;见上一节。
②显式(explicit)类型转换:为什么要有?因为这种转换有精度的丢失,编译器要你明明白白的写出来,让你知道有精度的丢失,也要转换数据类型。
*有可能丢失精度(甚至发生错误)的转换,即cast(铸造):在数据前面加个圆括号:(T)x,T里面为强转后的数据类型。
例如:
uint x = 65536;
ushort y = (ushort)x;//这样才能成立,因为ushoort的最大值比x小
具体见语言定义文档6.2.1;注意强制类型转换时由有符号类型向无符号类型转换,符号位拿来当数据了肯定会丢失精度。所以在对有符号类型进行强转时要格外注意。
*拆箱
*使用Convert类:
首先:如下情况:
string str1=Console.ReadLine();//ReadLine方法是读取一行输入
string str2 = Console.ReadLine();
Console.WriteLine( str1+str2);//
若输入:12 12则输出的是1212,原因为由于操作符与数据类型相关联,当+识别到左右两边的数据都是string类型时则把两个字符串连接起来,得到的就是1212的字符串而不是我们想要的值24。
正确做法为: int x = Convert.ToInt32(str1);
int y = Convert.ToInt32(str2);
这个例子就是非常常见的数据类型转换例子。
有的数据类型不能使用cast这种方式如int和string这两种数据类型差距太大。这时需要借助工具类(如Convert类)来进行类型转换。如: Convert.ToInt32(x);这个类相当于一个类型转换枢纽,几乎可以把当前数据类型转换成全部想要的数据类型。
*ToString方法与各类数据类型的Parse/TryParse方法:
有时候我们需要把其他数据如int转化为字符串类型数据这时候有两种方法可以选择:
第一种:调用Conver类的ToString静态方法: Convert.ToString(36种重载形式);详见”强制类型转换ToString”
第二种:调用数值类型数据的ToString实例(非静态)方法来完成转换: x.ToString(3个重载);ToString方法但就是把实例转化为一个字符串,创建一个Object对象:object o;o.会出现四个方法其中就有”ToString”说明所有的数据类型都有这个方法(一切数据类型都由object派生)
Parse(解析):这里的th1.Text和th2.Text都是字符串类型(string)
double x = double.Parse(th1.Text);
double y = double.Parse(th2.Text);
可以这样改写,小小的缺点:只能解析格式正确的数据如()里输入1ab格式不对就不能自动解析并转换为double类型。
这时可以使用TryParse方法: double x = double.TryParse();
具体涉及内容以后会讲。
③自定义数据类型转换操作符
示例;*操作符的本质就是方法的简记法
例如:创建了两个类:
class Stone
{
public int Age;
}
class Monkey
{
public int Age;
}
在main函数中进行类型转换:
Stone stone = new Stone();
Monkey m = (Monkey)stone;
显然不行编译器不知道给怎么转换,我们要告诉它,由于是stone进行类型转换所以在stone类里面添加具体语句:
class Stone
{
public int Age;
public static explicit operator Monkey(Stone stone)//可以理解为显式类型转换操作符就是一个目标类型的实例的构造器,但是这个构造器不是写在目标类型的类里面而是写在被转换的数据类型里面(而前面有四个操作符public static explicit operator ).
{
Monkey m = new Monkey();
m.Age = stone.Age / 500;//表示如何转换
return m;
}
}
这样编译器就知道要怎么转换了,继续回到main函数:
Stone stone = new Stone();
stone.Age = 5000;
Monkey m = (Monkey)stone;
Console.WriteLine(m.Age);
按照stone类里面定义(m.Age = stone.Age / 500;)的对stone对象进行转换,输出为:10;
该方式为显式转换,隐式只需要: public static implicit operator Money(Stone stone)
即把 explicit改成implicit然后类型转换时: Money m = stone;可以把stone对象的前缀(Money)省略。
4.4、算术运算符:详见语言定义文档7.8.1
务必留意”类型提升”:算术运算符都会产生,默认的类型提升如int型的数据与double的数据相乘为了不丢失精度,int型先隐式转换为double再进行计算。
“/“整数除法要注意除0异常,浮点数的除法没有该异常。
double a = double.PositiveInfinity;//正无穷大
double b = double.NegativeInfinity;//负无穷大
double x=(double)5/4;
结果为浮点型的1.25因为()类型转换操作符优先级大于算术运算符,所以先对5进行类型转换为double再进行除法,除法过程中运算符发现两边类型不同进行”类型提升”
有时候取余操作符%也会进行”类型提升”,也有浮点数取余。
4.5、位移操作符:<<(左移)、>>(右移)
表示:数据在内存当中的2进制的结构向左或者向右进行一定位数的平移:
int x = 7;
int y = x << 1;//x左移一位
string strx = Convert.ToString(x, 2).PadLeft(32, '0');
string stry = Convert.ToString(y, 2).PadLeft(32, '0');
Console.WriteLine(strx);
Console.WriteLine(stry);
输出显示为:00000000000000000000000000000111
00000000000000000000000000001110明显左移了一位
当没有溢出的情况下左移就是×2右移就是÷2.
移位过多会产生溢出由于默认是unchecked所以不会有异常。
*左移无论是正负数补进来的都是0,右移如果操作的是正数最高位补进来的是0,负数则补1;
4.6、关系操作符<,>,<=,>=;
所有关系操作符的运算结果都是布尔类型的,除了可以比较数值类型还可以比较字符类型。
char char1='a';
char char2='A';
ushort u1 = (ushort)char1;
ushort u2 = (ushort)char2;结果为u1=97;u2=65,;(对应Unicode码表)
还可以比较字符串,只能比是否相等。
string str1 = "ABc";
string str2 = "Abc";
Console.WriteLine(str1.ToLower()==str2.ToLower());都转换为小写输出结果为相等。
还可以调用: string.Compare();返回正值则第一个大于第二个,负值则小于,0则相等,比较方式为把两个字符串对齐依次比较字母对应的Unicode码。
4.7、类型检验操作符,is,as
is操作符结果是布尔类型,作用为检验某个对象是否为某个类(可以判断分类):
Teacher t=new Teacher();
Var result=t is Teacher;
Var result=t is Animal;//由于Teacher的父类为Animal所以这个判断也为true;反过来不行
as操作符的作用为:
Object o=new Teacher();
Teacher t=o as Teacher;即如果o对象是Teacher类则把o对象的地址交给Teacher类的引用变量t,否则把null值给t。
4.8、逻辑位与(&),逻辑位或(|),逻辑按位异或(^);
所谓位与就是按位求与,求与时把1当做真,0当做假,真&真为真,真&假为假,假&假为假。例如:
int x = 7;
int y = 28;
int z = x & y;
string strx = Convert.ToString(x, 2).PadLeft(32, '0');
string stry = Convert.ToString(y, 2).PadLeft(32, '0');
string strz = Convert.ToString(z, 2).PadLeft(32, '0');
Console.WriteLine(strx);
Console.WriteLine(stry);
Console.WriteLine(strz);
输出结果为:
00000000000000000000000000000111
00000000000000000000000000011100
00000000000000000000000000000100
按位或(|),真|真为真,假|真为真,假|假为假。
按位异或(^),两位相同为真,不同为假。
4.9、条件与(&&),条件或(||):用来操作布尔类型的值,最后结果也是布尔类型的值。
条件与(&&):左右两边都是真,整体值才为真;条件或(||):左右两边有一个真整体即为真。
条件与(&)与条件或(|)具有短路效应: if (x>y&&a++>3)当条件较多时条件与只要发现左边的值为假则不用判断右边的值了直接返回false,条件或情况类似,如果左边为真则直接返回true。
*由于存在该效应我们写代码时要尽量避免。
4.10、null合并操作符(??):
int ? y=null;//相当于暂时给y赋null值以后可变
int c = y ?? 1;//判断y是否为null是就用1赋值给y。
4.11、条件操作符:?:(是唯一一个可以接收三个数的操作符):就是if..else分支的简写:
y = (x >= 60) ? 100 : 0;表示x如果>=60就把100赋值给y否则把0赋值给y,往往用圆括号把条件括起来提高可读性。
4.12、(优先级最低)赋值表达式与lambda表达式:=,+=,%=,-=,>>=,<<=,&=,^=,|=
表示先运算再赋值,lambda表达式(=>)后面会讲到。
不过都要注意数据类型,运算符会根据两边的数据类型来判断进行的是整数运算还是浮点数运算还是其他。*赋值运算符的运算顺序是从右到左。例如:
Int x=3;
Int y=4;
Int z=5;
Int a=x+=y+=Z;先算右边的y+=z即y=y+z;...
C#基础操作符详解(下)的更多相关文章
- C#基础操作符详解(上)
本节内容: 1.操作符概览: 2.操作符的本质: 3.操作符与运算顺序 4.操作符详解. 1.操作符概览: 操作符(Operator)也译为”运算符” 操作符是用来操作数据的,被操作符操作的数据称为操 ...
- I2C 基础原理详解
今天来学习下I2C通信~ I2C(Inter-Intergrated Circuit)指的是 IC(Intergrated Circuit)之间的(Inter) 通信方式.如上图所以有很多的周边设备都 ...
- SQL Server 执行计划操作符详解(3)——计算标量(Compute Scalar)
接上文:SQL Server 执行计划操作符详解(2)--串联(Concatenation ) 前言: 前面两篇文章介绍了关于串联(Concatenation)和断言(Assert)操作符,本文介绍第 ...
- SQL Server 执行计划操作符详解(2)——串联(Concatenation )
本文接上文:SQL Server 执行计划操作符详解(1)--断言(Assert) 前言: 根据计划,本文开始讲述另外一个操作符串联(Concatenation),读者可以根据这个词(中英文均可)先幻 ...
- RabbitMQ基础知识详解
什么是MQ? MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取队列中 ...
- Nmap扫描教程之基础扫描详解
Nmap扫描教程之基础扫描详解 Nmap扫描基础扫描 当用户对Nmap工具了解后,即可使用该工具实施扫描.通过上一章的介绍,用户可知Nmap工具可以分别对主机.端口.版本.操作系统等实施扫描.但是,在 ...
- jmeter 基础功能详解
jmeter 基础功能详解 thread group:包含一组线程,每个线程独立地执行测试计划. sampler:采样器,有多种不同的sample实现,用来发起各种请求,如http请求,jdbc请求, ...
- Cisco路由技术基础知识详解
第一部分 请写出568A的线序(接触网络第一天就应该会的,只要你掐过,想都能想出来) .网卡MAC地址长度是( )个二进制位(16进制与2进制的换算关系,只是换种方式问,不用你拿笔去算) A.12 ...
- RabbitMQ,Apache的ActiveMQ,阿里RocketMQ,Kafka,ZeroMQ,MetaMQ,Redis也可实现消息队列,RabbitMQ的应用场景以及基本原理介绍,RabbitMQ基础知识详解,RabbitMQ布曙
消息队列及常见消息队列介绍 2017-10-10 09:35操作系统/客户端/人脸识别 一.消息队列(MQ)概述 消息队列(Message Queue),是分布式系统中重要的组件,其通用的使用场景可以 ...
随机推荐
- JDOJ3007 铺地板I
JDOJ3007 铺地板I https://neooj.com/oldoj/problem.php?id=3007 题目描述 有一个大小是 2 x N(1 <= N <= 105)的网格, ...
- Apache 监听 ipv4
查看端口信息 ifconfig 发现只有 ipv6 的 80 端口被监听,ipv4 的 80 端口没有被监听 因此通过 ipv4 无法访问 tcp6 0 0 :::80 :::* LISTEN 221 ...
- hasattr、getattr、setattr、delattr、反射
目录 hasattr getattr setattr delattr 反射的应用 __import__(了解) 思考: 在做程序开发中,我们常常会遇到这样的需求:需要执行对象里的某个方法,或需要调用对 ...
- ABP docker发布
环境:CentOS 7.6 64位 linux基本命令: cd:进入某个文件夹 mkdir:创建文件夹 ls:显示文件 ll:罗列出当前文件或目录的详细信息 判断是文件 还是文件夹: Linux系统中 ...
- [RN] React Native 调试技巧
React Native 调试技巧 一. 安卓模拟器调出Dev Setting 命令 adb shell input keyevent 二.图片不出来时,先运行此命令,再重新 run react-na ...
- [东西]neverOpen
一.介绍 用于完成一项光荣而伟大的使命. 二.更新日志 当前版本:V5.0 - 20191107 --------------------------------------------------- ...
- 【day05】php
一.时间日期函数库 1.安装:时间日期函数库PHPCORE组成部分 2. (1)date_default_timezone_set(string $timezone) 设置时区 ...
- Node.js 获取本机Mac地址
首先我们要先加载一个包用于获取mac地址 npm install getmac 加载完毕会在node_modules文件夹下发现一个getmac文件夹,我们把对应的路径加载到程序中 源码如下: var ...
- Paper | Xception: Deep Learning with Depthwise Separable Convolutions
目录 故事 Inception结构和思想 更进一步,以及现有的深度可分离卷积 Xception结构 实验 这篇论文写得很好.只要你知道卷积操作或公式,哪怕没看过Inception,也能看懂. 核心贡献 ...
- C++ 基于rapidjson对json字符串的进行序列化与反序列化
json字符串的解析以封装在我们开发过程中经常见到, 尤其在socket通信上面, 在一次项目中碰到json字符串的进行解析, 而公司有没有封装好的库, 于是就自己基于开源的库进行了一次封装, 接下是 ...