C#基础操作符详解(上)
本节内容:
1.操作符概览;
2.操作符的本质;
3.操作符与运算顺序
4.操作符详解。
1.操作符概览:

操作符(Operator)也译为”运算符”
操作符是用来操作数据的,被操作符操作的数据称为操作数(Operand)
表格从上往下优先级递减,同一行运算符的优先级一样一般按从左到右算,
“=”赋值操作符,是先运算右边的值再运算左边的值,所以是最后运算的。
2.操作符的本质
①操作符的本质是函数(即算法)的”简记法”
假如没有发明”+”只有Add函数,算式3+4+5将可以写成Add(Add(3,4),5)
假设没有发明”*”只有Mul函数,那么算式3+4*5将只能写成Add(3,Mul(4,5))
可见有操作符可读性更强。
②操作符不能脱离与它关联的数据类型(比如double数据类型的除法与int类型的除法相同数据结果不同)
可以说操作符就是与固定数据相关联的一套基本算法的简记法。
示例:为自定义的数据类型创建操作符。(格式为把方法名字改为”operator 想要定义的操作符”如:”operator +”)如下例子进一步说明了C#里面的操作符就是方法,也就是函数的一个简记法。
class Person
{
public string Name;
//public static List<Person>GetMary(Person p1, Person p2)(一般方法自定义操作符之前)
public static List<Person>operator +(Person p1, Person p2)
{
List<Person> people = new List<Person>();
people.Add(p1);
people.Add(p2);
for (int i = ; i < ; i++)
{
Person child = new Person();
child.Name = p1.Name + "&" + p2.Name + "'s child";
people.Add(child);
}
return people;
}
}
3.操作符与运算顺序
①操作符的优先级
可以使用圆括号提高被括起来的表达式的优先级。
圆括号可以嵌套。
不像数学里面有方括号和花括号,在C#语法中”[]”与”{}”有专门的用途。
②同优先级操作符的运算顺序
除了带有赋值功能的操作符,同优先级操作符都是有左到右进行运算,
带有赋值功能的操作符的运算顺序是由右到左(比如赋值运算符”=”),
与数学运算不同,计算机语言的同优先级运算没有”结合率”:
3+4+5只能理解为Add(Add(3,4),5)不能理解为Add(3,Add(4,5)。
- 操作符详解
4.1基本操作符
①(成员访问操作符)”.”操作符(上表中写为X.Y):四种功能;
*访问命名空间当中的子集命名空间;
*访问名称空间当中的类型;
*访问类型的静态成员(静态成员隶属于类本身故用类可以访问,而用类的对象不能访问类的静态成员);
*访问对象的成员(包括数据成员和方法);
②方法调用操作符”()”即方法后面跟着的那对圆括号(上表写为f(x))。
调用方法一定要加圆括号,但是:
Action myAction = new Action(c.PrintHello);//把PrintHello方法交给委托对象myAction管理
myAction();//这样在委托对象后面加个圆括号就相当于调用了被它管理的方法了,
这个时候PrintHello方法可以不带圆括号。
③元素访问操作符”[]”
int[] myIntArray = new int[13];//创建int数组的实例13个元素
int[] myIntArray2 = new int[]{1,2,3,4,5};//也可以在后面加花括号输入相应值,这对或括号叫做"初始化器",[]里不写数组大小会根据初始化器自动赋值...
myIntArray[0]=2;//访问的是第一个数组元素,访问数组元素,[]里写的是偏移量,从0开始。
Dictionary<string, Student> stuDic = new Dictionary<string, Student>();//一个类名后面,跟着一个尖括号表示这个类是泛型
//泛型是不完整的类如Dictionary<string, Student>在尖括号里要说明索引的类型(string)与值的类型(Student)(顺带一提Dictionary是一个字典类型)
*总结元素访问操作符”[]”里面放的是索引里面不一定是整数,如以下举例。
class Program
{
static void Main(string[] args)
{
Dictionary<string, Student> stuDic = new Dictionary<string, Student>();//一个类名后面,跟着一个尖括号表示这个类是泛型
//泛型是不完整的类如Dictionary<string, Student>在尖括号里要说明索引的类型(string)与值的类型(Student)(顺带一提Dictionary是一个字典类型)
for (int i = ; i < ; i++)
{
Student stu = new Student();
stu.Name = "s_" + i.ToString();
stu.Score = +i;
stuDic.Add(stu.Name, stu);//把stu放进字典里面,所以为stu.Name,值为stu
}
Student number6 = stuDic["s_6"];//说明了[]里不一定是整数,而一定是索引
Console.WriteLine(number6.Score);
}
}
class Student
{
public string Name;
public int Score;
}
④x--与x++:叫做后置的加加和后置的减减:
Int x=100; int y=x++;结果为x=101;y=100;因为x++是先赋值再进行自增;
--x与++x:叫做前置的加加和前置的减减:先进行自增或自减后进行赋值。
⑤typeof()操作符和default()操作符
*typeof操作符的作用为查看变量的种类:
Type t = typeof(int);
Console.WriteLine(t.Namespace);
Console.WriteLine(t.FullName);
Console.WriteLine(t.Name);
*Default操作符使操作数取默认值:数值型为0,引用型为null,
int x=default(int);//default操作的类型为结构体类型即数值类型时就返回内存块当中为0的值:
Console.WriteLine(x);
输出为0;
Form myForm = default(Form);//default操作数的类型为引用类型时就返回内存块当中为0的值即为null
Console.WriteLine(myForm==null);
输出为true;
当为枚举型enum时: Level level=default(Level);
Console.WriteLine(level);
enum Level
{
Mid,
Low,
High
}
结果为Mid,如果把Mid的位置和Low互换则结果为Low,这是因为当default操作符遇到枚举类型会把它当做数值型来处理,即第一个元素为0,后面的依次+1;
如果这样写:
enum Level
{
Mid=1,
Low=0,
High=2
}则返回值为Low。当用default获取枚举值的时候要小心,如果这样写:
enum Level
{
Mid=1,
Low=3,
High=2
}返回值为0,出错了,所以在设置枚举值时最好给元素一个0的整数值。
先说明:关键字var:帮助生成隐式类型变量:
int x;//显式变量,明确的告诉了编译器x属于什么数据类型;
var y;//隐式变量,告诉编译器y的类型暂时不知道,当我赋值的时候看着办
C#是强类型语言变量一旦确定数据类型就不可以变更。
⑥new操作符:
*帮助我们在内存当中创建一个类型的实例并且立刻调用这个实例的实例构造器(所谓的构造函数),并取得的实例地址....
new Form();//调用默认实例构造器
创建这个实例之后如果没有任何变量去引用它,访问它,过一会垃圾收集就把这个实例所占用的堆内存当做垃圾给收回来了。
*除了创建实例和调用实例构造器之外还能把new取得的实例地址通过赋值符号交给负责访问这个实例的变量。这样就在变量和实例之间构成了引用关系。有了这个引用关系之后就可以通过这个变量来访问实例。如: Form myForm=new Form();//调用默认实例构造器
myForm.Text = "Hello!";//通过变量来访问实例
*上面为主要功能,以下为附加功能:调用实例的初始化器:
Form myForm = new Form() {Text="Hello!" };在实例后面加花括号里面加属性的值。
可以初始化多个属性,中间逗号隔开。
还有:有的时候用实例只是一次性的没必要创建一个引用变量去初始化它,可以采用这时初始化器就发挥作用了:new Form(){Text=”Hello!”}.ShowDialog();只是由于没有引用变量引用(没有小孩牵着这个气球,气球一会就飞走了)所以一段时间后,垃圾回收器把它的堆内存回收。
a、错觉:要创建类的实例就一定要使用new操作符,错误的。如string Name = "Hello!";
String是一个类,创建实例时不用new操作符,这种方式叫做C#的”语法糖衣”,原因为为了统一使string与int的书写格式,而把string类的new操作符隐藏起来了,string可以用new但平常不这么用。类似的还有数组:
用new操作符:
int[] myArray = new int[10];//由于int的实例构造器有点特殊不用圆括号调用;
不用new操作符时:
int[] myArray = { 1,2,3,4};
b、new操作符特殊用法:为匿名类型创建实例,
Form myForm=new Form(){Text=”Hello!”};当为非匿名类型创建实例时new后面要加类型名,
当为匿名类型创建实例时:如:
Var person=new {Name=”Mr li”,Age=34};//new操作符后面不跟类型,直接用初始化器初始化实例,什么类型?让编译器根据初始化内容自行判断,不过该实例一定要有引用变量引用,不知道类型?用var隐式变量即可。那到底是什么类型呢?
Console.WriteLine(Person.GetType().Name);
输出为:<>f__AnonymousType0`2
“<>f__AnonymousType”为约定的前缀,0表示我在程序中创建的第一个,’2表示这个类型为泛型类,构成这个类型的时候你需要两个类型来构成它,哪两个类型呢?就是初始化器里面的一个是string,一个是int。这是在创建匿名类型时编译器自己识别的类型。
这里才真正体现出var类型(全部)功能的强大之处与重要性。因为如上一种情况就算你想写出它的类型也不知道叫什么名字。
*记住new操作符与var隐式变量组合的使用方法:是为匿名对象创建对象并且用隐式类型变量来引用这个实例。
c、new操作符有危险性(功能强大伴随的滥用风险)一旦在某个类里面(比如main函数隶属的Program类)用new操作符创建了某个类的实例(比如在main函数中创建Form类),那么这个类(Form)就与主类(Program)紧紧耦合在一起,Pragram类就紧紧依赖于Form类,一旦某个类(Form)出现问题,整个耦合体都无法正常运行。即new操作符会造成紧耦合。那怎么解决?在软件工程有项非常重要和实用的技术叫做”设计模式”,在”设计模式”当中有一种非常重要的模式叫做”依赖注入”(dependenty injection),该模式就是帮助我们把紧耦合变成相对松的耦合。有概念即可:new操作符有风险慎用,大型程序中为了避免有紧耦合的情况我们有一种叫做”依赖注入”的设计模式可以使用,实现不必关注。
*程序设计追求”高内聚低耦合”
d、new关键字的多用性(不是操作符而是关键字):如
class Student
{
public void Report()
{
Console.WriteLine("I'm a student");
}
}
class CsStudent:Student
{
new public void Report()//这叫子类对父类方法的隐藏,这里的new便不是操作符而是修饰符用来修饰new后面的方法的。(并不常见)
{
Console.WriteLine("I'm a Cstudent");
}
}
则 Student stu = new Student();
stu.Report();
CsStudent csStu = new CsStudent();
csStu.Report();时分别调用各自的Report()方法。
⑦checked()和unchecked()操作符:用来检查()内的值在内存中是否有溢出:(Overflow)
C#是强类型语言,任何一个变量它在内存里面都有数据类型,而数据类型有个非常重要的作用就是表示这种数据类型的实例在内存当中能够占多大的空间,一个值在内存空间所占的大小决定了这个值能够表达的范围,一旦超出这个范围这个值就产生了溢出。Checked就是告诉我们要去检出溢出,unchecked则告诉我们不用:
uint x = uint.MaxValue;
Console.WriteLine(x);
string binStr = Convert.ToString(x, 2);
Console.WriteLine(binStr);
try
{
uint y = checked(x + 1);//检测x+1是否溢出,溢出后去catch捕获异常
Console.WriteLine(y);
}
catch (OverflowException ex)
{
Console.WriteLine("There is overflow");
}
Unchecked()操作符表示不用检查,C#中默认该种方式。Checked也有其他用法:
Checked
{
try
{
uint y = checked(x + 1);//检测x+1是否溢出,溢出后去catch捕获异常
Console.WriteLine(y);
}
catch (OverflowException ex)
{
Console.WriteLine("There is overflow");
}
}
直接判断整个语句块中所有语句是否有溢出。
⑧delegate操作符(关键字)最主要的作用为声明一种叫委托的数据类型,委托是C#非常重要的概念。本节主要讲其作为操作符的作用(非常稀有因为拉姆达表达式(Lambda Expressions)的出现就是来替代delegate当做操作符的场景):使用delegate生成匿名方法:
this.myButton.Click +=delegate (object sender, RoutedEventArgs e)//使用delegate声明了一个匿名方法
{
this.myTextBox.Text = "Hello World!";
};
程序原本应为:this.myButton.Click += myButton_Click;
void myButton_Click(object sender, RoutedEventArgs e)
{
this.myTextBox.Text = "Hello World!";
}
现在替代这用用法的拉姆达表达式:
this.myButton.Click += (sender, e)=>
{
this.myTextBox.Text = "Hello World!";
};
语法的演变可见C#语法越来越简洁,功能越来越强大。
⑨sizeof()操作符:
a、只能获取结构体类型在内存中所占字节数,默认情况下:sizeof只能去获取基本数据类型他们的实例在内存当中所占的字节数,基本数据类型:比如int、uint...说白了就是C#关键字里面那些除了string和object的数据类型:因为这两个为引用类。
b、在非默认的情况下可以使用sizeof去获取自定义的结构体类型的实例它在内存中占的字节数,但是需要把它放在不安全的上下文当中:
unsafe
{
int x=sizeof(Student);
}
Decimal数据类型精确度比double高占16个字节;
⑩最后一个”基本操作符”:”->”
*类(class)属于引用类型,结构体(struct)属于值类型。C#中有严格的规定像指针操作,取地址操作,用指针去访问成员的操作,只能用来操作结构体类型,不能用它们去操作引用体类型。(Class)
要运行不安全代码除了要把它放在unsafe{}里面,还要再项目->最后一项(相应项目属性)->生成->勾选”允许生成不安全代码”,所谓双重保险。
使用该操作符时要在unsafe情况下使用:
unsafe
{
Student stu;
stu.ID = 1;
stu.Score = 99;
Student*pStu=&stu;
pStu->Score = 100;
Console.WriteLine(stu.Score);
}
C#基础操作符详解(上)的更多相关文章
- C#基础操作符详解(下)
书接上文的基本操作符,下文介绍的是其他操作符: 4.2一元操作符: 只要有一个操作数跟在它后面就可以构成表达式,也叫单目操作符. ①&x和*x操作符(很少见有印象即可): 这两个操作符同样也需 ...
- I2C 基础原理详解
今天来学习下I2C通信~ I2C(Inter-Intergrated Circuit)指的是 IC(Intergrated Circuit)之间的(Inter) 通信方式.如上图所以有很多的周边设备都 ...
- C++框架_之Qt的窗口部件系统的详解-上
C++框架_之Qt的窗口部件系统的详解-上 第一部分概述 第一次建立helloworld程序时,曾看到Qt Creator提供的默认基类只有QMainWindow.QWidget和QDialog三种. ...
- 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请求, ...
- hadoop基础-SequenceFile详解
hadoop基础-SequenceFile详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.SequenceFile简介 1>.什么是SequenceFile 序列文件 ...
- Cisco路由技术基础知识详解
第一部分 请写出568A的线序(接触网络第一天就应该会的,只要你掐过,想都能想出来) .网卡MAC地址长度是( )个二进制位(16进制与2进制的换算关系,只是换种方式问,不用你拿笔去算) A.12 ...
随机推荐
- JavaScript之JSON&AJAX
今天为大家讲解JavaScript中非常流行的数据传输形式JSON和异步技术AJAX技术. 一 JSON JSON的全称是JavaScript Object Notation(js对象表示法),它是一 ...
- ActiveMQ消息选择器Selector
一.前言 消息发送到Broker,消费者通过Destination可以订阅消费某个特定的通道内的消息.一些特殊情况下,需要消费者对消息过滤下再进行消费,也就是筛选出某些特定消息.ActiveMQ提供了 ...
- 品Spring:能工巧匠们对注解的“加持”
问题的描述与方案的提出 在Spring从XML转向注解时,为了自身的开发方便,对注解含义进行了扩充(具体参考本号上一篇文章). 这个扩充直接导致了一个问题,就是需要从注解往元注解以及元元注解(即沿着从 ...
- Apache Thrift 的基本使用
Apache Thrift 的基本使用 可以先看看官网是如何介绍的 The Apache Thrift software framework, for scalable cross-language ...
- Janus安装教程,ubuntu18.04系统
Janus安装教程,ubuntu18.04系统 本文介绍Jansu如何安装,操作系统为Ubuntu 18.04. (1)安装git 执行命令:“sudo apt-get install ...
- idea 环境变量设置编码
1.打开Run/Debug Configuration,选择你的tomcat 2.然后在 Server > VM options 设置为 -Dfile.encoding=UTF-8
- Jquery Ztree异步加载树
1. 下载jquery的JS文件/ztree的CSS文件和JS文件 https://jquery.com/download/ https://gitee.com/zTree/zTree_v3/tree ...
- Kubernetes 系列(一):本地k8s集群搭建
我们需要做以下工作: (1)安装VMware,运行CentOs系统,一个做master,一个做node. (2)安装K8s. (3)安装docker和部分镜像会需要访问外网,所以你需要做些网络方面的准 ...
- 品Spring:对@Resource注解的处理方法
@Resource是Java的注解,表示一个资源,它具有双向的含义,一个是从外部获取一个资源,一个是向外部提供一个资源. 这其实就对应于Spring的注入和注册.当它用在字段和方法上时,表示前者.当它 ...
- 编程小技巧之 Linux 文本处理命令
合格的程序员都善于使用工具,正所谓君子性非异也,善假于物也.合理的利用 Linux 的命令行工具,可以提高我们的工作效率. 本文简单的介绍三个能使用 Linux 文本处理命令的场景,给大家开阔一下思路 ...