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

时间:2022-04-21 19:20:38

运算符和类型强制转换


1.运算符

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

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

运算符的简化操作

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

条件运算符:

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

condition?true_value:false_value

checked和unchecked运算符:

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

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

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

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

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

is运算符:

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

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

as运算符:

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

object o1="Some String";
object o2=; 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 + ;//b=null
int? c = a * ;//c=null

空合并运算符??:

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

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

int? a = null;
int b; b = a ?? ;//b has the value 10
a = ;
b = a ?? ;//b has the value 3
运算符的优先级

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

3.类型的安全性

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

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

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

Cannot implicitly convert type 'int' to 'type'

隐式转换:

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

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

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

C#支持的隐式类型转换

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

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

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

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

装箱和拆箱

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

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

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

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

int myIntNumber = ;
object myObject = myIntNumber;

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

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

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方法

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

静态的Equals方法

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

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

比较运算符(==):

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

比较值类型的相等性

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

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();
}
}
}

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

Box1 的体积:
Box2 的体积:
Box3 的体积:

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

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

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(, );
float f = balance;
}

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

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

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

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

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

下面代码会正常运行

Currency balance = new Currency(, ); 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());
}

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

类之间类型强制转换:

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

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

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

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

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

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

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

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

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

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

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