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 = 0; i < 11; 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)。

  1. 操作符详解

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是一个字典类型)

*总结元素访问操作符”[]”里面放的是索引里面不一定是整数,如以下举例。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Dictionary<string, Student> stuDic = new Dictionary<string, Student>();//一个类名后面,跟着一个尖括号表示这个类是泛型
 6             //泛型是不完整的类如Dictionary<string, Student>在尖括号里要说明索引的类型(string)与值的类型(Student)(顺带一提Dictionary是一个字典类型)
 7             for (int i = 1; i < 100; i++)
 8             {
 9                 Student stu = new Student();
10                 stu.Name = "s_" + i.ToString();
11                 stu.Score = 100+i;
12                 stuDic.Add(stu.Name, stu);//把stu放进字典里面,所以为stu.Name,值为stu
13             }
14             Student number6 = stuDic["s_6"];//说明了[]里不一定是整数,而一定是索引
15             Console.WriteLine(number6.Score);
16         }
17     }
18     class Student
19     {
20         public string Name;
21         public int Score;
22     }

④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);

}

原文地址:https://www.cnblogs.com/AhuntSun-blog/p/11746613.html

时间: 2024-08-03 22:31:57

C#基础操作符详解(上)的相关文章

Linux上命令的使用格式和基础命令详解

一.Linux上命令的使用格式 命令行提示符详解: 用户通过终端的命令行接口来控制操作系统,登陆后如下: [[email protected] ~]# root: 当前登录的用户 @:分隔符 localhost: 当前主机的主机名,非完整格式:此处的完整格式为:localhost.localdomain [[email protected] ~]# hostname localhost.localdomain ~:用户当前所在的目录(current directory),也称为工作目录(work

halcon基础数据类型详解

#if defined(__CHAR_UNSIGNED__) || defined(__sgi) #define INT1 signed char /* integer, signed 1 Byte */ #define INT1_MIN SCHAR_MIN #define INT1_MAX SCHAR_MAX #else #define INT1 char /* integer, signed 1 Byte */ #define INT1_MIN CHAR_MIN #define INT1_M

Nmap扫描教程之基础扫描详解

Nmap扫描教程之基础扫描详解 Nmap扫描基础扫描 当用户对Nmap工具了解后,即可使用该工具实施扫描.通过上一章的介绍,用户可知Nmap工具可以分别对主机.端口.版本.操作系统等实施扫描.但是,在实施这些扫描工作之前,需要先简单了解下Nmap工具的使用,以方便后面实施扫描.所以,本章将通过使用Nmap工具实施基础的扫描,来帮助用户了解该工具. Nmap扫描扫描概述 在实施基本的扫描之前,需要先了解一些Nmap网络扫描的基本知识,及需要考虑的一些法律边界问题.本节将对网络基本扫描进行一个简单介

jmeter 基础功能详解

jmeter 基础功能详解 thread group:包含一组线程,每个线程独立地执行测试计划. sampler:采样器,有多种不同的sample实现,用来发起各种请求,如http请求,jdbc请求,javaTest请求等等. logic controller:逻辑控制器有多种不同的实现,可以决定每个sample的执行顺序. listener:有多种不同的实现,主要用于统计测试接话运行中的数据并展示,如可以进行图形化方式展示响应时间. timer:定时器,有多种不同的实现,可用作每个请求见的停顿

高性能Web服务之tomcat基础应用详解(一)

Tomcat概述: Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache.Sun 和其他一些公司及个人共同开发而成.由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范.因为Tomcat 技术先进.性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目

varnish基础概念详解

varnish基础概念详解 比起squid更加轻量级,大致有以下几个特点: ·可以基于内存缓存,也可以在磁盘上缓存,但是就算存放在磁盘上,也不能实现持久缓存 只要进程崩溃,此前缓存统统失效,无论是在内存还是在磁盘,但是现在已经具备持久缓存功能,但是仍然在实验阶段,经常容易崩溃,而且最大大小不能超过1G 如果期望内存大小超过几十个G,比如图片服务器,纯粹使用内存,性能未必好,这时候可以使用磁盘进行缓存,或SSD X 2 做RAID 避免磁盘损坏,在实现随机访问上 ssd硬盘要比机械硬盘要好的多,如

Tomcat基础配置详解

Tomcat基础配置详解 组件原理图如下: 任何tomcat实例就是一个server,而一个server内部要想能够解析jsp页面转义编译serlet程序,要靠其引擎来实现 而引擎才是真正意义上执行jsp代码的容器,都是tomcat用类来描述这些组件的 同时,为了接受用户的请求,需要基于connector组件,所谓监听的套接字的程序,能够接手用户的请求,被称为连接器 一个server内部可以完全运行N个引擎,无非就是运行多个虚拟机而已 war包的概念 放在网页目录可以直接访问,而部署的时候可以自

Servlet基础知识详解

Servlet基础知识详解 Servlet基础知识详解 Servlet程序执行全过程 Servlet映射路径 Servlet映射练习 Servlet生命周期 为什么要学习Servlet生命周期 Servlet重要的生命周期方法 模拟通过反射构造Servlet对象 Servlet单实例多线程 Servlet留给开发者的init方法 Servlet中核心对象学习 HttpServletRequest对象 HttpServletResponse对象 ServletConfig对象 ServletCon

SQL Server 执行计划操作符详解(2)——串联(Concatenation )

本文接上文:SQL Server 执行计划操作符详解(1)--断言(Assert) 前言: 根据计划,本文开始讲述另外一个操作符串联(Concatenation),读者可以根据这个词(中英文均可)先幻想一下是干嘛的.其实还是挺直观,就是把东西连起来,那么下面我们来看看到底连什么?怎么连?什么时候连? 简介: 串联操作符既是物理操作符,也是逻辑操作符,在中文版SQL Server的图形化执行计划中称为"串联",在其他格式及英文版本中称为"Concatenation".