一元操作符:只能操作一个操作数。
+ - ! ~ ++x --x (T)x await &x *x
最不常用的就是&x取地址操作符和引用操作符*x。
上一节我们定义的Student结构体:
Student* pStu = &stu;
取地址之后赋值给一个指针变量。指针变量定义:类名后跟星号* 空格 变量名。
通过引用操作符也可以直接拿到对象。此时就可以用点来操作。之前用指针地址只能用指向操作符。
但是点这个操作符也就是成员访问操作符属于基本操作符,级别要比一元操作符优先级要高。所以:为了改变优先级要加圆括号。
(*pStu).Score = 1000;
以上两个操作符,现实中很少用到。
~取反操作符:
将一个数,按照二进制上的数,按位取反。
static void Main(string[] args)
{
int x = 12345678;
int y = ~x;
string xStr = Convert.ToString(x, 2).PadLeft(32, '0');//补0对齐。
string yStr = Convert.ToString(y, 2).PadLeft(32, '0');
Console.WriteLine(xStr);
Console.WriteLine(yStr);
}
-求相反数
计算机中求相反数的做法是:将二进制按位取反,再加一。
int x = int.MinValue;
int y = -x;
Console.WriteLine(y);
string xStr = Convert.ToString(x, 2).PadLeft(32, '0');//补0对齐。
string yStr = Convert.ToString(y, 2).PadLeft(32, '0');
Console.WriteLine(xStr);
Console.WriteLine(yStr);
-2147483648
-2147483648
10000000000000000000000000000000
10000000000000000000000000000000
按位取反最小值,是0111...1。然后如果加1,那么就又成为了100....0。还是原来的数。
强制类型转换操作符(T)x
- 隐式(implicit)类型转换
- 不丢失精度的转换:
- 子类向父类的转换
- 装箱(子类向父类赋值)
- 显示(explicit)类型转换
- 有可能丢失精度(甚至发生错误)的转换,即cast(铸造的意思)
- 拆箱(父类变为子类)
- 使用Convert类
- ToString方法与个数据类型的Parse/Tryparse方法
- 自定义类型转换操作符
- 示例
隐藏在类型转换符背后的原理:石头变猴子。
显示变化:
class Program
{
static void Main(string[] args)
{
Stone stone = new Stone();
stone.Age = 5000;
Monkey wukongSun = (Monkey)stone;
Console.WriteLine(wukongSun.Age);
}
}
class Stone
{
public int Age;
public static explicit operator Monkey(Stone stone)
{
Monkey m = new Monkey();
m.Age = stone.Age / 500;
return m;
}
}
class Monkey
{
public int Age;
}
隐式变换:
class Program
{
static void Main(string[] args)
{
Stone stone = new Stone();
stone.Age = 5000;
Monkey wukongSun = stone;
Console.WriteLine(wukongSun.Age);
}
}
class Stone
{
public int Age;
public static implicit operator Monkey(Stone stone)
{
Monkey m = new Monkey();
m.Age = stone.Age / 500;
return m;
}
}
class Monkey
{
public int Age;
}
数值运算符
double x = double.PositiveInfinity; // 正无穷大
double y = double.NegativeInfinity; // 负无穷大
double result = x / y;
Console.WriteLine(result); // Nan
数值提升,避免牺牲精度。
double x = (double)5 / 4;
Console.WriteLine(x);
is、as类型检测操作符
is判断一个对象是不是某个类型的对象。
as对象像某个类。
逻辑运算符
&&:条件与:具有短路性。
int x = 3;
int y = 4;
int a = 3;
if (x>y && a++>3)
{
Console.WriteLine("是否短路了呢?");
}
Console.WriteLine(a);
返回值为3。因为&&只要判断了前置条件不符合,后面的条件连执行都不执行了,直接短路了。所以a的值没有变化。
||:条件或:也具有短路性。
int x = 5;
int y = 4;
int a = 3;
if (x>y || a++>3)
{
Console.WriteLine("是否短路了呢?");
}
Console.WriteLine(a);
返回值还是为3。因为条件或发现,前面这个条件为true。后面的都懒得看了。因此也短路了。
可控类型??
有这样一个应用场景。比如登记学生的成绩:但是有个同学没有交卷,暂时没法填写他的分数。只要他交卷了,就有得分。此时不能写0,因为0分也是得分。直接写int x = null,编译无法通过。为了标记引入了可控类型(泛型类型)。
Nullable<int> x = null;
x = 100;
Console.WriteLine(x);
Console.WriteLine(x.HasValue);
可控类型非常有用,所以C#引入了关键字问号?。
int? x = null;
x = 100;
但是如果太多了,不好一一查找,最后清洗的时候,希望null值可以赋值。那么
int? x = null;
int y = x ?? 1;
Console.WriteLine(y);
条件操作符?:
唯一一个可以接受三个操作数的运算符。其实就是if...else的简写。
int x = 90;
string str = x >= 60 ? "pass" : "failed";
Console.WriteLine(str);