欢迎您来到“名字什么都是浮云”的博客空间!

C#高级编程9-第7章 运算符和类型强制转换

运算符和类型强制转换


 

1.运算符

 

 

 

运算符的简化操作

条件运算符:

if-else的简化操作,也称三元运算符。如果条件为真,返回一个值,为假返回另外一个值。

condition?true_value:false_value

checked和unchecked运算符:

如果把一个代码块标记为checked,CLR会执行溢出检查,如果溢出,会抛出OverflowException异常,运行以下代码会抛出异常。

byte b=255;
checked
{
    b++;
}
Console.WriteLine(b.ToString());

如果要禁止溢出检查,将checked改为unchecked

unchecked是默认行为,只有在需要把几行未检查的代码放在一个显式地标记为checked的大代码块中,才需要显式使用unchecked

byte b=255;
unchecked
{
    b++;
}
Console.WriteLine(b.ToString());

is运算符:

is运算符可以检查对象是否与特定的类型兼容。“兼容”表示对象是否该类型,或者派生自该类型

int i=10;
if(i is object)
{
  Console.WriteLine("i is an object");
}

as运算符:

as运算符执行引用类型的显式转换。如果转换的类型与指定的类型兼容,则转换成功,否则返回null

object o1="Some String";
object o2=5;

string s1=o1 as string;//s1="Some String"
string s2=o2 as string;//s2=null

sizeof运算符

使用sizeof运算符可以确定栈中值类型需要的长度(单位:字节)

Console.WriteLine(sizeof(int));

如果对复杂类型(非基本类型)使用sizeof运算符,就需要把代码放在unsafe块中

unsafe
{
 Console.WriteLine(sizeof(int));
}

typeof运算符:

typeof运算符返回一个特定类型的Type对象,typeof(string)返回一个String类型的Type对象。

 

可空运算符?和运算符:

对于布尔类型,可以给它指定true或false值。但是要把该类型的值定义为undefined;这时候就可以使用可空类型,考虑null值和各种运算符一起使用的影响。

int? a= null;
int? b= a + 4 ;//b=null
int? c = a * 5 ;//c=null

空合并运算符??:

可以处理可空类型和引用类型时表示null可能的值。这个运算符放在两个操作数之间。第一个操作数必须是可空类型或引用类型。第二个操作数必须与第一个操作数类型相同,或者可以隐含地转换为第一个操作数的类型。空合并运算符的计算如下:
1.如果第一个操作数不是null,整个表达式就等于第一个操作数的值。
2.如果第一个操作数是null,整个表达式就等于第二个操作数的值。

如果a是null默认等于10;如果不是null;a就是3;

int? a = null;
int b;

b = a ?? 10;//b has the value 10
a = 3 ;
b = a ?? 10;//b has the value 3

 

运算符的优先级

 

3.类型的安全性

我们需要把一种类型转换为需要的另一种类型。

类型转换
byte value1 = 10;
byte value2 = 23;
byte total;
total = value1 + value2;
Console.WriteLine(total);

在试图编译这些代码时,会得到错误信息

Cannot implicitly convert type 'int' to 'type'

隐式转换:

只要值没有发生改变。类型转换就可以自动(隐式)进行

byte value1 = 10;
byte value2 = 23;
long total;
total = value1 + value2;
Console.WriteLine(total);

当2个byte类型相加时,实际上和的值已经变成long类型了,这时候不需要任何的类型强制转换。

 

C#支持的隐式类型转换

可空类型不能隐式的转换为非可空类型。必须通过显式转换。

不能进行显式转换的情况:

 

装箱和拆箱

装箱和拆箱是值类型和引用类型之间相互转换是要执行的操作。 

1. 装箱在值类型向引用类型转换时发生

2. 拆箱在引用类型向值类型转换时发生

拆箱操作的执行过程和装箱操作过程正好相反,是将存储在堆上的引用类型值转换为值类型并给值类型变量。

int myIntNumber = 20;
object myObject = myIntNumber;

int的基类是object类型,因为所有类型都继承自object类;子类转父类是隐式转换。父类转子类是显式转换。

object number = 20;
int sum = (int)number + 2;

4.比较对象的相等性

比较引用类型的相等性

RefernceEquals方法
RefernceEquals方法是一个静态方法,测试两个引用是否引用类的同一个实例。特别是两个引用是否包含内存中相同地址。方法不能重写。如果提供的两个引用是引用同一个对象实例。则返回true,否则返回false

SomeClass x, y;
x = new SomeClass();
y = new SomeClass();
bool B1 = ReferenceEquals(null, null);//true
bool B2 = ReferenceEquals(null, x);//false
bool B3 = ReferenceEquals(x, y);//true

虚拟的Equals方法

静态的Equals方法

比较运算符(==):

比较运算符只做值进行比较,不做引用比较。

比较值类型的相等性

 

5.运算符重载

您可以重定义或重载 C# 中内置的运算符。因此,程序员也可以使用用户自定义类型的运算符。重载运算符是具有特殊名称的函数,是通过关键字 operator 后跟运算符的符号来定义的。与其他函数一样,重载运算符有返回类型和参数列表。

例如,请看下面的函数:

public static Box operator+ (Box b, Box c)
{
   Box box = new Box();
   box.length = b.length + c.length;
   box.breadth = b.breadth + c.breadth;
   box.height = b.height + c.height;
   return box;
}

上面的函数为用户自定义的类 Box 实现了加法运算符(+)。它把两个 Box 对象的属性相加,并返回相加后的 Box 对象。

运算符重载的实现

下面的程序演示了完整的实现:

using System;

namespace OperatorOvlApplication
{
   class Box
   {
      private double length;      // 长度
      private double breadth;     // 宽度
      private double height;      // 高度

      public double getVolume()
      {
         return length * breadth * height;
      }
      public void setLength( double len )
      {
         length = len;
      }

      public void setBreadth( double bre )
      {
         breadth = bre;
      }

      public void setHeight( double hei )
      {
         height = hei;
      }
      // 重载 + 运算符来把两个 Box 对象相加
      public static Box operator+ (Box b, Box c)
      {
         Box box = new Box();
         box.length = b.length + c.length;
         box.breadth = b.breadth + c.breadth;
         box.height = b.height + c.height;
         return box;
      }

   }

   class Tester
   {
      static void Main(string[] args)
      {
         Box Box1 = new Box();         // 声明 Box1,类型为 Box
         Box Box2 = new Box();         // 声明 Box2,类型为 Box
         Box Box3 = new Box();         // 声明 Box3,类型为 Box
         double volume = 0.0;          // 体积

         // Box1 详述
         Box1.setLength(6.0);
         Box1.setBreadth(7.0);
         Box1.setHeight(5.0);

         // Box2 详述
         Box2.setLength(12.0);
         Box2.setBreadth(13.0);
         Box2.setHeight(10.0);

         // Box1 的体积
         volume = Box1.getVolume();
         Console.WriteLine("Box1 的体积: {0}", volume);

         // Box2 的体积
         volume = Box2.getVolume();
         Console.WriteLine("Box2 的体积: {0}", volume);

         // 把两个对象相加
         Box3 = Box1 + Box2;

         // Box3 的体积
         volume = Box3.getVolume();
         Console.WriteLine("Box3 的体积: {0}", volume);
         Console.ReadKey();
      }
   }
}
View Code

当上面的代码被编译和执行时,它会产生下列结果:

Box1 的体积: 210
Box2 的体积: 1560
Box3 的体积: 5400

下表描述了 C# 中运算符重载的能力:

 

 

 

6.用户定义的类型强制转换

实现用户定义的类型强制转换

在这个示例中,定义一个结构Currency,包含一个正的USD($)金额,C#为次提供了decimal类型,但如果需要进行复杂的财务处理。可以编写自己的结构和类来表示相应的金额。在这样的类上实现特定的方法。

struct Currency
{
        public uint Dollars;
        public ushort Cents;

        public Currency(uint dollars, ushort cents)
        {
            Dollars = dollars;
            Cents = cents;
        }

        public override string ToString()
        {
            return string.Format("${0}.{1,-2:00}", Dollars, Cents);
        }

        public static implicit operator float(Currency value)
        {
            return value.Dollars + (value.Cents / 100.05f);
        }
}
static void Main(string[] args)
{

    Currency balance = new UnitTestProject1.Currency(10, 50);
    float f = balance;
}

如果将float类型给balance则不能进行转换。

float f = 10.5f;
Currency balance = new UnitTestProject1.Currency(10, 50);
balance = f;

然后我们在Currency类再添加一个方法

public static explicit operator Currency(float value)
{
     uint dollbars = (uint)value;
     ushort cents = (ushort)((value-dollbars)*100);
     return new Currency(dollbars, cents);
}

下面代码会正常运行

Currency balance = new Currency(50, 35); Console.WriteLine(balance);
Console.WriteLine("balance is " + balance);
Console.WriteLine("balance is(using ToString()) " + balance.ToString());
float balance2 = balance;
Console.WriteLine("After converting to float,=" + balance2);
balance = (Currency)balance2;
Console.WriteLine("After converting back to Currency,=" + balance);
Console.WriteLine("Now attempt to convert out of range value of " + "-$50.50 to aCurrency:");
checked
{
     balance = (Currency)(50.50);
     Console.WriteLine("Result is " + balance.ToString());
}

类之间类型强制转换:

如果某个类派生自另一个类,就不能定义两个类之间的类型强制转换。
类型强制转换必须在源数据类型或目标数类型的内部定义。

 

基类与派生类之间强制转换:

派生类实现了基类,基类转为派生类,这种情况是可以转换成功的

基类转派生类,这种情况是不能转换成功的。

MyBase derivedObject=new MyDerived();
MyBase baseObject=new MyBase();
MyDerived derivedCopy1=(MyDerived)derivedObject; //ok
MyDerived derivedCopy2=(MyDerived)baseObject;//Throws Exception

装箱与拆箱之间强制转换:

 从基本类型到object类型是一种隐式的强制转换。因为这种强制转换是从派生类到基类的转换。

Currency balance=new Currency(40,0);
object baseCopy=balance;

对于基类的子类实现。由基类转换为子类。需要显示的强制转换。

object derivedObject=new Currency(40,0)
object baseObject=new object();
Currency derivedCopy1=(Currency)derivedObject;//ok
Currency derivedCopy2=(Currency)baseObject;//Exception
多重类型的强制转换

 如果方法调用带有多个重载方法,并要给该方法传递参数。而该参数的数据类型不匹配任何重载方法,就可以迫使编译器确定使用哪些强制转换方式进行数据转换,从而决定使用哪个重载方法(并进行相应的数据转换)

 

posted @ 2017-05-10 13:44  名字什么都是浮云  阅读(273)  评论(0编辑  收藏  举报