zoukankan      html  css  js  c++  java
  • C#图解教程 第八章 表达式和运算符

    表达式和运算符

    表达式


    本章将定义表达式,并描述C#提供的运算符。 
    运算符是一个符号,它表示返回单个结果的操作。操作数(operand)指作为运算符输入的数据元素。一个运算符会:

    • 将操作数作为输入
    • 执行某个操作
    • 基于该操作返回一个值

    表达式是运算符和操作数的字符串。可以作为操作数的结构有:

    • 字面量
    • 常量
    • 变量
    • 方法调用
    • 元素访问器,如数组访问器和索引器
    • 其他表达式

    例:下面的表达式,有3个运算符和4个操作数


    字面量


    字面量(literal)是源代码中键入的数字或字符串,表示一个指定类型的明确的、固定的值。

    例:字面量

    class Program
    {
        static void Main()
        {
            Console.WriteLine("{0}",1024);//整数字面量
            Console.WriteLine("{0}",3.1416F);//浮点型字面量
            Console.WriteLine("{0}",true);//布尔型字面量
        }
    }

    对于引用类型变量,字面量null表示变量没有设置为内存中的数据。

    整数字面量

    例:不同的整数类型

    236  //整型
    236L //长整型
    236U //无符号整型
    236UL//无符号长整型

    整数字面量还可以写成十六进制(hex)形式


    实数字面量

    实数字面量组成如下:

    • 十进制数字
    • 可选的小数点
    • 可选的指数部分
    • 可选的后缀

    例:实数字面量的不同格式

    float f1=236F;
    double d1=236.712;
    double d2=.351;
    double d3=6.338e-26;

    无后缀的实数字面量默认是double类型。

    字符字面量

    字符字面量可以是下面任意一种:

    • 单个字符
    • 简单转义序列:反斜杠+单个字符
    • 十六进制转义序列:反斜杠+大写或小写x+4个十六进制数
    • Unicode转义序列:反斜杠+大写或小写u+4个十六进制数

    例:字符字面量的不同格式

    char c1='d';
    char c2='
    ';
    char c3='x0061';
    char c4='u005a';

    一些特殊字符及其编码见下图


    字符串字面量

    两种字符串字面量类型:

    • 常规字符串字面量
    • 逐字字符串字面量

    常规字符串字面量包含:

    • 字符
    • 简单转义序列
    • 十六进制和Unicode转义序列
    string st1="Hi there!";
    string st2="Val	5,val	10";
    string st3="Addx000ASomeu0007Interest";

    逐字字符串以@为前缀,它有以下特征:

    • 逐字字符串与常规字符串区别在于转义字符串不会被求值。在双引号中间的所有内容,包括通常被认为是转义序列的内容,都被严格按字符串中列出的那样打印
    • 逐字字符串的唯一例外是相邻的双引号组,它们被解释为单个双引号字符
    string rst1="Hi there!";
    string vst1=@"Hi there!";
    string rst2="It started,"Four score and seven..."";
    string vst2=@"It started,""Four score and seven...""";
    string rst3="Value 1 	 5,val2 	 10";
    string vst3=@"Value 1 	 5,val2 	 10";
    string rst4="C:\Program Files\Microsoft\";
    string vst4=@"C:Program FilesMicrosoft";
    string rst5=" Print x000A Multiple u000A Lines";
    string vst5=@" Print
        Multiple
        Lines";

    编译器让相同的字符串字面量共享堆中同一内存位置以节约内存

    求值顺序


    表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式最终值发生差别。

    优先级

    正如小学的先乘除再加减,C#中运算符也有优先级。


    结合性

    表达式中运算符优先级不同的,从高到低依次运算。但若是运算符优先级相同怎么办? 
    当连续运算符有相同优先级时,求值顺序由操作结合性决定。

    • 左结合运算符从左至右
    • 右结合运算符从右至左
    • 除赋值运算符外,其他二元运算符都是左结合
    • 赋值运算符和条件运算符是右结合

    简单算术运算符


    求余运算符


    求余运算符(%)用第二个操作数除第一个操作数,并返回余数。 
    求余运算符是二元左结合运算符。

    • 0%3=0,因为0除3得0余0
    • 2%3=2,因为2除3的0余2
    • 4%3=1,因为4除3得1余1

    关系比较运算符和相等比较运算符


    它们都是二元左结合运算符,对其操作数进行比较并返回bool值。

    与C和C++不同,在C#中数字不具有布尔意义

    int x=5;
    if(x)//错,x是int类型,不是布尔型
    if(x==5)//对,返回true

    比较操作和相等性操作 
    对于大多数引用类型来说,比较它们的相等性,将只比较它们的引用。

    • 如果引用相等,即它们指向内存中相同对象,相等性为true,否则为false,即使内存中两个分离的对象在所有其他方面完全相等。
    • 这称为浅比较

    下图阐明了引用类型的比较

    • 图左边,a和b两者引用相同,返回true
    • 图右边,引用不同,所以即使内容相同,也返回false

    string类型也是引用类型,但它的比较方式不同。比较字符串的相等性,将比较它们的长度和内容(区分大小写)

    • 如果两个字符串长度和内容相等则返回true,即使它们占用不同内存区域
    • 这称为深比较(deep comparison)

    将在第15章介绍的委托也是引用类型,并且也使用深比较。比较委托的相等性时,让两个委托都是null,或两者的调用列表有相同数目成员,并且调用列表想匹配,则返回true。 
    比较数值表达式,将比较类型和值。比较enum类型时,比较操作数的实际值。枚举在第13章阐述。

    递增运算符和递减运算符


    无论运算符前置还是后置,只影响返回给表达式的值。在语句执行后,最终存放在操作数的变量的值相同


    条件逻辑运算符


     

    条件逻辑运算符使用“短路”(short circuit)模式操作,意思是,如果计算Expr1之后结果已确定,那么它会跳过Expr2的求值。 
    例:短路示例

    bool bVal;
    bVal=(1==2)&&(2==2);
    //左侧false,接着&&运算,结果必是false,所以跳过了右侧的运算
    bVal=(1==1)||(1==2);
    //左侧true,接着是||运算,结果必是true,所以跳过了右侧的运算

    因为短路特性,不要在Exp2中放置带有副作用的表达式(比如改变一个值),因为可能不会计算。

    bool bVal;int iVal=10;
    bVal=(1==2)&&(9==iVal++);//结果:bVal=False,iVal=10;
           ↑             ↑
         False        不会计算

    逻辑运算符


    移位运算符


    例:移位运算符示例

    • 操作数14的每个位向左移动3个位置
    • 右边结尾腾出位置用0补充
    • 结果为112

     

     

    int a,b,x=14;
    a=x<<3;
    b=x>>3;
    Console.WriteLine("{0}<<3={1}",x,a);
    Console.WriteLine("{0}>>3={1}",x,b);

    赋值运算符


    赋值运算符是二元右结合运算符

    复合赋值 
    复合赋值运算符允许一种速记方法,在某些情况下避免左边的变量在右边重复出现。 
    复合赋值不仅更短,也易于理解。

    x=x+(y-z);
    x+=y-z;

    条件运算符


    条件运算符是一种强大且简洁的方法,基于条件的结果,返回两个值之一。 
    条件运算符是三元运算符

    • 格式:Condition?Expression1:Expression2
    • Condition必须返回一个bool类型的值
    • 如果Condition求值为true,那么对Expression1求值并返回。否则,对Expression2求值并返回
    if...else
    if(x<y)
        intVar=5;
    else
        intVar=10;
    条件运算符
    intVar=x<y?5:10;

    if…else语句是控制流语句,它应当用来做两个行为中的一个。条件运算符返回一个表达式,它应当用于返回两个值中的一个。

    用户定义的类型转换


    用户定义的转换将在第16章详讲,在这里稍微提一下。

    • 可以为自己的类和结构定义隐式和显式转换。这允许把用户定义类型的对象转换成某个其他类型
    • C#提供隐式转换和显示转换
      • 隐式转换,当决定在特定上下文中使用特定类型时,如有必要,编译器会自动执行转换
      • 显式转换,编译器只在使用显式转换运算符时才执行转换

    声明隐式转换的语法如下。

           必需的                    目标类型          源数据
             ↓                          ↓               ↓
    public static implicit operator TargetType(SourceType Identifier)
    {
        ...
        return ObjectOfTargetType;
    }

    显式转换的语法与之相同,但要用explicit替换implicit

    例:将LimitedInt转换为int

    class LimitedInt
    {
        const int MaxValue=100;
        const int MinValue=0;
        public static implicit operator int(LimitedInt li)
        {
            return li.TheValue;
        }
        public static implicit operator LimitedInt(int x)
        {
            var li=new LimitedInt();
            li.TheValue=x;
            return li;
        }
        private int _theValue=0;
        public int TheValue
        {
            get{return _theValue;}
            set
            {
                if(value<MinValue)
                    _theValue=0;
                else
                    _theValue=value>MaxValue?MaxValue:value;
            }
        }
        class Program
        {
            static void Main()
            {
                LimitedInt li=500;
                int value=li;
                Console.WriteLine("li:{0},value:{1}",li.TheValue,value);
            }
        }
    }

    显式转换和强制转换运算符 
    如果把两个运算符声明为explicit,你将不得不在实行转换时显示使用转换运算符。

        public static explicit operator int(LimitedInt li)
        {
            return li.TheValue;
        }
        public static explicit operator LimitedInt(int x)
        {
            var li=new LimitedInt();
            li.TheValue=x;
            return li;
        }
        static void Main()
        {
            LimitedInt li=(LimitedInt)500;
            int value=(int)li;
            Console.WriteLine("li:{0},value:{1}",li.TheValue,value);
        }    

    输出结果与上例相同

    另外有两个运算符,接受一种类型的值,并返回另一种不同的、指定类型的值。这就是is运算符和as运算符。它们将在第16章结尾阐述。

    运算符重载


    运算符重载允许你定义C#运算符应该如何操作自定义类型的操作数

    • 运算符重载只能用于类和结构
    • 声明必须同时使用static和public修饰符
    • 运算符必须是要操作的类或结构的成员

    例:类LimitedInt的两个重载运算符,加运算符和减运算符

    class LimitedInt
    {
             必需的        类型    关键字 运算符         操作数
               ↓           ↓        ↓     ↓             ↓
        public static LimitedInt operator + (LimitedInt x,double y)
        {
            var li=new LimitedInt();
            li.TheValue=x.TheValue+(int)y;
            return li;
        }
        public static LimitedInt operator - (LimitedInt x)
        {
            var li=new LimitedInt();
            li.TheValue=0;
            return li;
        }
        ...
    }
    运算符重载的限制

    不是所有的运算符都能被重载,可以重载的类型也有限制。 
     
    递增和递减运算符可重载。但和预定义的版本不同,重载运算符的前置和后置之间没有区别。 
    运算符重载不能做下面的事情:

    • 创建新运算符
    • 改变运算符的语法
    • 重新定义运算符如何处理预定义类型
    • 改变运算符的优先级或结合性

    重载运算符应该符合运算符的直观含义。

    运算符重载的示例

    例:LimitedInt的3个运算符重载

    class LimitedInt
    {
        const int MaxValue=100;
        const int MinValue=0;
        public static LimitedInt operator - (LimitedInt x)
        {
            var li=new LimitedInt();
            li.TheValue=0;
            return li;
        }
        public static LimitedInt operator - (LimitedInt x,LimitedInt y)
        {
            var li=new LimitedInt();
            li.TheValue=x.TheValue-y.TheValue>0?(x.TheValue-y.TheValue):0;
            return li;
        }    
        public static LimitedInt operator + (LimitedInt x,double y)
        {
            var li=new LimitedInt();
            li.TheValue=x.TheValue+(int)y;
            return li;
        }    
        private int _theValue=0;
        public int TheValue
        {
            get{return _theValue;}
            set
            {
                if(value<MinValue)
                    _theValue=0;
                else
                    _theValue=value>MaxValue?MaxValue:value;
            }
        }
        class Program
        {
            static void Main()
            {
                var li1=new LimitedInt();
                var li2=new LimitedInt();
                var li3=new LimitedInt();
                li1.TheValue=10;li2.TheValue=26;
                Console.WriteLine("li:{0},li2:{1}",li1.TheValue,li2.TheValue);
                li3=-li1;
                Console.WriteLine("-{0}={1}",li1.TheValue,li3.TheValue);
                li3=li2-li1;
                Console.WriteLine("{0}-{1}={2}",li2.TheValue,li1.TheValue,li3.TheValue);
                li3=li1-li2;
                Consoel.WriteLine("{0}-{1}={2}",li1.TheValue,li2.TheValue,li3.TheValue);
            }
        }
    }

    typeof运算符


    typeof运算符返回作为其参数的任何类型的System.Type对象。

    例:使用typeof运算符获取SomeClass类的信息

    using System.Reflection;//反射
    class SomeClass
    {
        public int Field1;
        public int Field2;
        public void Method1(){}
        public int Method2(){return 1;}
    }
    class Program
    {
        static void Main()
        {
            var t=typeof(SomeClass);
            FieldInfo[] fi=t.GetFields();
            MethodInfo[] mi=t.GetMethods();
            foreach(var f in fi)
                Console.WriteLine("Field:{0}",f.Name);
            foreach(var m in mi)
                Console.WriteLine("Method:{0}",m.Name);
        }
    }

    GetType方法也会调用typeof运算符,该方法对每个类型的每个对象都有效。 
    例:使用GetType获取对象类型名称

    class SomeClass
    {
    }
    class Program
    {
        static void Main()
        {
            var s=new SomeClass();
            Console.WriteLine("Type s:{0}",s.GetType().Name);
        }
    }

    其他运算符


    本章介绍的运算符是内置类型的标准运算符。本书后面部分会介绍其他特殊用法的运算符及操作数类型。例如,可空类型有一个特殊运算符叫空接合运算符(第25章)。

    from: http://www.cnblogs.com/moonache/p/6140985.html

  • 相关阅读:
    使用 asp.net mvc和 jQuery UI 控件包
    ServiceStack.Redis 使用教程
    HTC T8878刷机手册
    Entity Framework CodeFirst 文章汇集
    2011年Mono发展历程
    日志管理实用程序LogExpert
    使用 NuGet 管理项目库
    WCF 4.0路由服务Routing Service
    精进不休 .NET 4.0 (1) asp.net 4.0 新特性之web.config的改进, ViewStateMode, ClientIDMode, EnablePersistedSelection, 控件的其它一些改进
    精进不休 .NET 4.0 (7) ADO.NET Entity Framework 4.0 新特性
  • 原文地址:https://www.cnblogs.com/GarfieldEr007/p/10126560.html
Copyright © 2011-2022 走看看