C#学习笔记5 操作符

操作符(详细

目录

优先顺序由上到下,同一级的由左到右,但是最后的赋值和lambda表达式则从右到左。

操作符是函数的简计法,操作符其实就是函数

image-20210320151319997

operator 对关键字进行重载

操作符是函数的简计法,操作符其实就是函数

(.()^.. 运算符无法进行重载。 [] 运算符也被视为非可重载运算符。 使用索引器以支持对用户定义的类型编制索引。)

operator 关键字的主要作用是用来重载运算符的,还可以用于类或结构中类型的自定义转换。

下面看个例子

image-20210320152627787

image-20210320152706150

x.y 成员访问运算符和表达式 .

Null 条件运算符 ?. 和 ?[]

Null 条件运算符在 C# 6 及更高版本中可用,仅当操作数的计算结果为非 null 时,null 条件运算符才会将成员访问 ?.元素访问 ?[] 运算应用于其操作数;否则,将返回 null。 即:

  • 如果 a 的计算结果为 null,则 a?.xa?[x] 的结果为 null
  • 如果 a 的计算结果为非 null,则 a?.xa?[x] 的结果将分别与 a.xa[x] 的结果相同。

checked

checked 关键字用于对整型类型算术运算和转换显式启用溢出检查。(显式即明显的,明确的 ,var是不显式,由编译器推断类型)

默认情况下,如果表达式仅包含常量值,且产生的值在目标类型范围之外,则会导致编译器错误。 如果表达式包含一个或多个非常量值,则编译器不检测溢出。

也就是说,int 溢出了,溢出会同余定理,不会报错,使用checked可以检测这些,抛出溢出异常,配合unchecked可以在checked范围中高出unchecked

new

匿名类型的实例化

要创建匿名类型的实例,请使用 new 运算符和对象初始值设定项语法:

var example = new { Greeting = "Hello", Name = "World" };
Console.WriteLine($"{example.Greeting}, {example.Name}!");
// Output:
// Hello, World!

重写与new

什么条件下才能对父类方法进行重写:父类中方法必须被virtual关键字修饰的方法才能被子类重写,如何父类方法没有使用virtual关键字,在子类中重写父类方法时就会编译错误;在子类中对父类进行重写时,需要使用override关键字作为标识;例如B类继承A类,并重写A类中Print方法时,没有使用override关键字的的话会出现警告,告诉我们这不是重写,这是隐式的new。

  class A
    {
        public A()
        {
            Print();
        }
        public virtual void Print()
        {
            Console.WriteLine("我是A类");
        }
    }
    class B : A
    {
        public B()
        {
            Print();
        }
        public  override void Print()
        {
            Console.WriteLine("我是B类");
        }
    }

如果使用new关键字对print方法进行修饰,B类中Print方法则不是对A类中Print方法进行重写,关于这一点我会在下面进行解读。

如果父类方法被子类重写之后,通过创建子类对象指向父类时,使用Print方法时,调用的是父类还是子类的方法?

A a = new B();
a.Print();

运行后的结果为:

img

在创建B类的实例时,首先会运行类中构造函数,但是会首先执行父类中的构造函数,当执行父类中构造函数中Print方法时,首先判断Print方法是否已经被重写,如果该方法被重写的话,则会执行子类中重写的方法;执行完成父类的构造函数之后,就会执行子类中构造函数,子类构造函数调用Print函数时,首先会判断子类中是否含有Print方法,有的话则会调用自身的Print方法,否则调用父类中Print方法;最后a.Print()也是首先判断A类中Print方法是否被重写,如果被重写的话则调用子类中Print方法。

因此得出的结论是:当父类方法被子类重写之后,只要创建子类的实例,当调用被重写的方法时,最终运行的都是子类中的方法。

如果子类中的Print方法被new关键字而不是override关键字修饰时,父类中Print方法是否被重写?

答:没有被重写。被new 关键字修饰后,Print方法不是重写方法,而是B类中的新方法。

class A
{
    public A()
    {
        Print();
    }
    public virtual void Print()
    {
        Console.WriteLine("我是A类");
    }
}
class B : A
{
    public B()
    {
        Print();
    }
    public  new void Print()
    {
        Console.WriteLine("我是B类");
    }
}

当将override改为new关键字之后,再次运行得到以下的结果:

img

这说明了当使用了new关键字之后,只要跟父类有关,运行的Print方法都是运行父类中Print方法。

取反~

获得把每位值取反,如果,整数变负数,负数绝对值+1,负数变整数,绝对值+1

指针相关运算符

可以使用以下运算符来使用指针:

有关指针类型的信息,请参阅指针类型

任何带指针的运算都需要使用 unsafe 上下文。 必须使用 -unsafe 编译器选项编译包含不安全块的代码。

x * y 乘法

整数乘法的时候如果int.MaxValue2 ,那么调用的是int operator * (返回类型位方法),就会导致返回值溢出,被checked出异常,但是如果有一个是int.MaxValue2L,int.MaxValue就会被隐式转换位long,然后用long operator *(返回类型位方法)

image-20210320214510226

​ 无穷大乘*会返回NaN(not a number)

image-20210320215202758

x / y除法

整数除法

对于整数类型的操作数,/ 运算符的结果为整数类型,并且等于两个操作数之商向零舍入后的结果:

Console.WriteLine(13 / 5);    // output: 2
Console.WriteLine(-13 / 5);   // output: -2
Console.WriteLine(13 / -5);   // output: -2
Console.WriteLine(-13 / -5);  // output: 2

若要获取浮点数形式的两个操作数之商,请使用 floatdoubledecimal 类型:

Console.WriteLine(13 / 5.0);       // output: 2.6

int a = 13;
int b = 5;
Console.WriteLine((double)a / b);  // output: 2.6

浮点除法

浮点没有除0异常,符号位(如果0是整数,那么0符号位无论如何都是正)正负决定了结果是正无穷(double.PositiveInfinity)还是负无穷(double.NegativeInfinity)

对于 floatdoubledecimal 类型,/ 运算符的结果为两个操作数之商:

Console.WriteLine(16.8f / 4.1f);   // output: 4.097561
Console.WriteLine(16.8d / 4.1d);   // output: 4.09756097560976
Console.WriteLine(16.8m / 4.1m);   // output: 4.0975609756097560975609756098

如果操作数之一为 decimal,那么另一个操作数不得为 floatdouble,因为 floatdouble 都无法隐式转换为 decimal。 必须将 floatdouble 操作数显式转换为 decimal 类型。 如需详细了解数值类型之间的转换,请参阅内置数值转换

image-20210320220540951

x % y 求余

余数运算符 % 计算左侧操作数除以右侧操作数后的余数。

整数余数

对于整数类型的操作数,a % b 的结果是 a - (a / b) * b 得出的值。 非零余数的符号与左侧操作数的符号相同,如下例所示:

Console.WriteLine(5 % 4);   // output: 1
Console.WriteLine(5 % -4);  // output: 1
Console.WriteLine(-5 % 4);  // output: -1
Console.WriteLine(-5 % -4); // output: -1

使用 Math.DivRem 方法计算整数除法和余数结果。

浮点余数

对于 floatdouble 操作数,有限的 xyx % y 的结果是值 z,因此

  • z(如果不为零)的符号与 x 的符号相同。
  • z 的绝对值是 |x| - n * |y| 得出的值,其中 n 是小于或等于 |x| / |y| 的最大可能整数,|x||y| 分别是 xy 的绝对值。

计算余数的此方法类似于用于整数操作数的方法,但与 IEEE 754 规范不同。 如果需要符合 IEEE 754 规范的余数运算,请使用 Math.IEEERemainder 方法。

有关非限定操作数的 % 运算符行为的信息,请参阅 C# 语言规范余数运算符章节。

对于 decimal 操作数,余数运算符 % 等效于 System.Decimal 类型的余数运算符

以下示例演示了具有浮动操作数的余数运算符的行为:

Console.WriteLine(-5.2f % 2.0f); // output: -1.2
Console.WriteLine(5.9 % 3.1);    // output: 2.8
Console.WriteLine(5.9m % 3.1m);  // output: 2.8

image-20210320221116202

+加法与-减法

正无穷+/-负无穷=NaN

x << y 左位移x >> y右位移

很十进制一样,左移就是乘10,右移是除10,计算机二进制也是这样,前提是不溢出,右移是容易溢出的,(左移最低位补0和右翼根据符号位补)

uint x = 0b_1100_1001_0000_0000_0000_0000_0001_0001;
Console.WriteLine($"Before: {Convert.ToString(x, toBase: 2)}");

uint y = x << 4;
Console.WriteLine($"After:  {Convert.ToString(y, toBase: 2)}");
// Output:
// Before: 11001001000000000000000000010001
// After:  10010000000000000000000100010000

is 判断类型是否兼容

如果 E 的结果为非 null 且可以通过引用转换、装箱转换或取消装箱转换来转换为类型 T,则 E is T 表达式将返回 true;否则,它将返回 falseis 运算符不会考虑用户定义的转换。

public class Base { }

public class Derived : Base { }

public static class IsOperatorExample
{
    public static void Main()
    {
        object b = new Base();
        Console.WriteLine(b is Base);  // output: True
        Console.WriteLine(b is Derived);  // output: False

        object d = new Derived();
        Console.WriteLine(d is Base);  // output: True
        Console.WriteLine(d is Derived); // output: True
    }
}
int i = 27;
Console.WriteLine(i is System.IFormattable);  // output: True

object iBoxed = i;
Console.WriteLine(iBoxed is int);  // output: True
Console.WriteLine(iBoxed is long);  // output: False
int i = 23;
object iBoxed = i;
int? jNullable = 7;
if (iBoxed is int a && jNullable is int b)
{
    Console.WriteLine(a + b);  // output 30
}

as

相当于下面的作用

E is T ? (T)(E) : (T)null

&与&&(|与||类似就不再搞了)

& 运算符计算操作数的逻辑与。 如果 xy 的计算结果都为 true,则 x & y 的结果为 true。 否则,结果为 false

即使左侧操作数计算结果为 false& 运算符也会计算这两个操作数,而在这种情况下,无论右侧操作数的值为何,运算结果都为 false

条件逻辑 AND 运算符 && 也计算操作数的逻辑 AND,但如果左侧操作数的计算结果为 false,它就不会计算右侧操作数。

^异或运算符

Console.WriteLine(true ^ true);    // output: False
Console.WriteLine(true ^ false);   // output: True
Console.WriteLine(false ^ true);   // output: True
Console.WriteLine(false ^ false);  // output: False

&位与

uint a = 0b_1111_1000;
uint b = 0b_1001_1101;
uint c = a & b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10011000

|位或

uint a = 0b_1010_0000;
uint b = 0b_1001_0001;
uint c = a | b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10110001

^位异或

uint a = 0b_1111_1000;
uint b = 0b_0001_1100;
uint c = a ^ b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 11100100

typeof

确认类型的

?

让a可以赋值为null(如果不赋值默认值0),而且提供HasValue属性

        int? a = null;
        Console.WriteLine(a.HasValue);
        Console.WriteLine(a.GetType().Name);

default

确认默认值的,有点麻烦,而在default(枚举类型时)默认选下标为0的,如果你建立的枚举中没有等于0的,显示0

image-20210320165643788

sizeof

计算占用字节大小的,关系到unsafe,比较麻烦,以后厉害点再说吧

因为操作内存,使用不安全的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值