C#学习笔记5

C#学习笔记5

开发环境:vs2022

1. 操作符的本质

  • 操作符的本质是函数(即算法)的“简记法”
  • 操作符不能脱离与他关联的数据类型
    • 可以说操作符就是与固定数据类型相关联的一套基本算法的简记法
    • 示例:为自定义数据类型创建操作符
    internal class Program
    {
        static void Main(string[] args)
        {
            Person person1 = new Person();
            Person person2 = new Person();
            person1.Name = "Deer";
            person2.Name = "Deer's wife";
            //List<Person> nation = Person.GetMarry(person1, person2);
            List<Person> nation = person1 + person2;	//使用这一操作符
            foreach (var p in nation)
            {
                Console.WriteLine(p.Name);
            }
        }
    }
    
    class Person
    {
        public string Name;
    
        //public static List<Person> GetMarry(Person p1, Person p2)   //泛型
        public static List<Person> operator +(Person p1, Person p2)   //把GetMarry这一方法定义为特定数据类型的操作符
        {
            List<Person> people = new List<Person>();
            people.Add(p1); //Add方法将往List集合末尾添加相应元素对象
            people.Add(p2);
            for(int i = 0; i < 11; i++)
            {
                Person child = new Person();
                child.Name = p1.Name + "&" + p2.Name + "'s child";
                people.Add(child);
            }
    
            return people;
        }
    }
    

2. c#中Add方法将往List集合末尾添加相应元素对象

List<Person> people = new List<Person>();
people.Add(p1); //Add方法将往List集合末尾添加相应元素对象
people.Add(p2);

3. 优先级与运算顺序

  • 操作符的优先级
    • 可以使用圆括号提高被括起来表达式的优先级
    • 圆括号可以嵌套
    • 不像数学里有方括号和花括号,在C#语言里“[]”与“{}”有专门的用途
  • 同优先级操作符的运算顺序
    • 除了带有赋值功能的操作符,同优先级操作符都是由左向右进行运算
    • 带有赋值功能的操作符的运算顺序是由右向左
    • 与数学运算不同,计算机语言的同优先级运算没有“结合率”,3+4+5只能理解为Add(Add(3, 4), 5)不能理解为Add(3, Add(4, 5))

4. 操作符详解

  • 在这里插入图片描述

  • 成员访问操作符:x.y

    • 用成员访问操作符来访问外层名称空间中的子集名称空间
    System.IO
    
    • 用成员访问操作符来访问名称空间中的类型
    System.IO.File
    
    • 用成员访问操作符来访问类型的静态成员
    System.IO.File.Create(args[0]);
    
    • 用成员访问操作符来访问实例里面的实例成员
    Form myForm = new Form();
    myForm.Text = "Hello world";
    
    • 用成员访问操作符来访问实例里面的方法
    myForm.ShowDialog();
    
  • 调用操作符:f(x)

    • 用调用操作符来调用方法
    • 也是实例构造器
    internal class Program
    {
    	static void Main(string[] args)
    	{
    	    Calculator c = new Calculator();
    	    double x = c.Add(3.0, 5.0);
    	    Console.WriteLine(x);
        }
    }
    class Calculator
    {
        public double Add(double a, double b)
        {
            return a + b;
        }
    }
    
  • 索引器操作符:a[i]

    • 方括号 [] 通常用于数组、索引器或指针元素访问
    • 括号中的索引不一定都是整数(后面学
    • 数组的示例
     //创建数组实例
    int[] myIntArray = new int[10];
    
  • 初始化器操作符:{}

    • 数组的示例
    int[] myIntArray = new int[] { 1, 2, 3, 4, 5 };
    
  • 后缀增量操作符:x++

    • 先使用后加1
    • 示例
    int x = 100;
    int y = x++;
    Console.WriteLine(x);   //101
    Console.WriteLine(y);   //100
    
  • 后缀递减操作符:x–
    与上面原理类似

  • typeof操作符

    • 用于获取某个类型的 System.Type 实例
    • 示例
    Type t = typeof(int);
    Console.WriteLine(t.Namespace);
    Console.WriteLine(t.FullName);
    Console.WriteLine(t.Name);
    int c = t.GetMethods().Length;
    foreach(var mi in t.GetMethods())
    {
        Console.WriteLine(mi.Name);
    }
    
    Console.WriteLine(c);
    

    结果如下
    在这里插入图片描述

  • default 运算符

    • 生成类型的默认值
    • 结构体类型的defoult值是0;引用类型的default值是NUll
    • 示例
    double x = default(double);	//结构体类型
    Console.WriteLine(x);   //0
    
    Form myForm = default(Form);	//引用类型
    Console.WriteLine(myForm==null);    //ture
    
    • 枚举类型的第一个元素为0,故默认打印第一个元素
    internal class Program
    {
        static void Main(string[] args)
        {  
            Level level = default(Level);	//枚举类型的默认值
            Console.WriteLine(level);	//Low
        }
    	enum Level
        {
            Low,
            Mid,
            High
        }
    }
    
    • 如果枚举类型传创建时自己赋值,且没有0,就可能会发生错误
  • new操作符 (当作操作符来使用)

    • var关键字:声明隐式类型的变量,由它自己判断变量的类型。
    int x = 100;    //显式
    
    var y = 100;    //隐式
    Console.WriteLine(y.GetType().Name);    //Int32
    var m = 100L;    //隐式
    Console.WriteLine(m.GetType().Name);    //Int64
    var n = 100D;    //隐式
    Console.WriteLine(n.GetType().Name);    //Double
    
    • c#是强类型语言,一旦确定变量的类型后,在后面的赋值中不能将他改为其他类型
    int x= 100;  
    x = "100";		//这里会报错
    

    错误 CS0029 无法将类型“string”隐式转换为“int”

    • new操作符的主要功能:在内存中创建类型的实例,并且立刻调用其实例构造器,如果在new操作符左边有赋值符号的话,new将拿到的实例的地址赋给前面的访问这个实例的变量。
    //创建实例Form,调用其实例构造器()
    new Form();
    
    //创建实例Form,调用其实例构造器(),将实例的地址赋值给引用变量myForm
    Form myForm = new Form();
    
    • new操作符的附加功能:调用实例的初始化器,可以初始化多个属性
    Form myForm = new Form() { Text = "Hello", FormBorderStyle = FormBorderStyle.SizableToolWindow };
    myForm.ShowDialog();
    


    标题,以及上方工具栏隐藏

    • 不使用引用变量,去初始化。不使用引用变量,只能执行一下,后面就被垃圾收集器回收。
    new Form() { Text = "Hello" }.ShowDialog();
    
    • 语法糖衣
      类类型创建实例的时候要使用new操作符,string也是类型型,但是它不用调用new操作符,是因为c#语法将new隐藏了。s数组也有类似的用法。
    string name = "Tim";
    int[] myArray = new int[10];
    int[] myArray1 = {1,2,3};
    
    • 匿名类型
    Form myForm = new Form();   //非匿名类型,名字Form
    var person = new { Name = "Mr.Okay", Age = 34 };    //匿名类型,new后面直接跟初始化为匿名类型创建实例,使用var去定义类型
    Console.WriteLine(person.Name); //显示Mr.Okay
    Console.WriteLine(person.Age);  //34
    

    此处var关键字的强大之处就体现出来了,因为这个类型都不知道是啥类型

    • new操作符不可以滥用,new操作符会和上面的类紧耦合,在编写大型程序时,有一种依赖注入模式会把这种紧耦合变成松耦合。
  • checked和unchecked操作符

    • 在 c# 中,checked 和 unchecked 是用于控制整数运算溢出检查的关键字。它们允许我们明确指定在进行整数运算时是否要检查溢出,以及如何处理溢出情况。
    • 在c#中,默认使用unchecked
    uint x = uint.MaxValue; //获取uint能表示的最大值
    Console.WriteLine(x);
    string binStr = Convert.ToString(x, 2); //转换成二进制
    Console.WriteLine(binStr);
    uint y = checked(x + 1);    //报错:未经处理的异常:  System.OverflowException: 算术运算导致溢出。
    Console.WriteLine(y); 
    
    • 使用 try-catch 语句处理在执行代码块期间可能发生的异常。 将代码置于 try 块中可能发生异常的位置。catch语句处理发生的异常
    • 操作符形式的用法
    //输出There's overflow!,checked检测溢出
    try
    {
        uint y = checked(x + 1);    
        Console.WriteLine(y);
    }
    catch (OverflowException)
    {
        Console.WriteLine("There's overflow!");
    }
    
    //输出0,unchecked不检测溢出
    try
    {
        uint y = unchecked(x + 1);
        Console.WriteLine(y);
    }
    catch (OverflowException)
    {
        Console.WriteLine("There's overflow!");
    }
    
    • 上下文形式的用法
    checked
    {
        try//使用 try-catch 语句处理在执行代码块期间可能发生的异常。 将代码置于 try 块中可能发生异常的位置。catch语句处理发生的异常
        {
            uint y = x + 1;
            Console.WriteLine(y);
        }
        catch (OverflowException)
        {
            Console.WriteLine("There's overflow!");
        }
    }
    
  • sizeof操作符

    • 使用sizeof操作符来获取基本类型在内存中所占的字节数,只能结构体类型
    int a = sizeof(int);
    Console.WriteLine(a);	//4
    
    int b = sizeof(double);
    Console.WriteLine(b);	//8
    
    • sizeof操作符可以在unsafe上下文中获取自定义结构体的内存大小
    static void Main(string[] args)
    {
        unsafe
        {
            int c = sizeof(Student);
            Console.WriteLine(c);		//16
        }
    
    struct Student
    {
        int ID;
        long Score;
    }
    

    unsafe要在项目——属性——生成——勾选“允许不安全代码”

  • ->取地址操作符 和 &x解引用操作符

    • 作用与c语言中的一样
    • 在c#中需要在unsafe上下文中使用
    • 只能操作结构体类型,不能操作引用类型
    static void Main(string[] args)
    {
        unsafe
    	{
    	  Student stu;
    	  stu.ID = 1;
    	  stu.Score = 99;
    	  Student* pStu = &stu;
    	  pStu->Score = 100;
    	  Console.WriteLine(stu.Score);
    	  (*pStu).Score = 1000;
    	  Console.WriteLine(stu.Score);
    	}
    }
    
    struct Student
    {
        public int ID;
        public long Score;
    }
    
  • +,-,~操作符

    • 常规加减用法与c语言一样
    • 对整型操作,如果是对字符串类型操作,则是把两个字符串接在一起
    • 负号取反取反要加括号
    int m = 100;
    int n = -m;
    Console.WriteLine(n);   //-100
    n = -(-m);
    Console.WriteLine(n);   //100
    
    • 用负号取反是对二进制每一位取反加1,用~取反只对每一位取反不加1
    • PadLeft函数是向左补齐32位,用0补齐
    int m = 1234567;
    int n = -m;
    //int n = ~m;
    string mStr = Convert.ToString(m, 2).PadLeft(32, '0');
    string nStr = Convert.ToString(n, 2).PadLeft(32, '0');
    Console.WriteLine(mStr);   //00000000000100101101011010000111
    Console.WriteLine(nStr);   //11111111111011010010100101111001
    
  • 取非操作符!

    • 对布尔类型取非
    bool b1 = false;
    bool b2 = !b1;
    Console.WriteLine(b2);
    
    • 例子
    internal class Program
    {
        static void Main(string[] args)
        {
            Student1 stu1 = new Student1(null);
            Console.WriteLine(stu1.Name);
        }
    }
    
    class Student1
    {
        public Student1(string initName)
        {
            if(!string.IsNullOrEmpty(initName))	//如果名字非空则使用
            {
                this.Name = initName;
            }
            else
            {
                throw new ArgumentException("initName cannot be null or empty!");	//名字空则报错
            }
        }
    
        public string Name;
    }
    
    • throw的用法看大佬文章:链接: link
  • ++x操作符 和 --x操作符

    • 先自增(自减)再使用
  • 类型转换操作符(T)x

    • 隐式类型(implicit)转换
      在这里插入图片描述

      • 不丢失精度的转换
      namespace ConversionExample
      {
            internal class Program
            {
                static void Main(string[] args)
                {
                    //不丢失精度的转换
                    int x = int.MaxValue;	//获取int类型的最大值
                    long y = x;	//转换
                    Console.WriteLine(y);	//2147483647
                }
            }
        }	  
      
      • 子类向父类的转换
        多的往少转换;
        继承用 " : "
      namespace ConversionExample
      {
          //子类向父类的转换(多的转成少的)
          internal class Program
          {
              static void Main(string[] args)
              {
                  Teacher t = new Teacher();
                  Human h = t;
                  Animal a = h;
                  a.Eat();    //多的转换成少的
              }
          }
      
          class Animal
          {
              public void Eat()
              {
                  Console.WriteLine("Eating...");
              }
          }
        
          class Human : Animal    //将Animal类作为该类的基类(父类),继承Animal类的方法
                                    //Human派生自Animal
          {
              public void Think()
              {
                  Console.WriteLine("Who I am?");
              }
          }
        
          class Teacher : Human    //将Animal类和Human作为该类的基类(父类)
          {
              public void Teach()
              {
                  Console.WriteLine("I teach class.");
              }
          }
      }
      
      • 装箱
    • 显式(explicit)类型转换
      在这里插入图片描述

      • 有可能丢失精度(甚至发生错误)的转换,即cast
      namespace ConversionExample
      {
      	internal class Program
      	{
      	    static void Main(string[] args)
      	    {
      	        Console.WriteLine(ushort.MaxValue); //65535
      	        uint x = 65536;
      	        ushort y = (ushort)x;   //直接ushort y = x;会报错
      	        Console.WriteLine(y);   //0      
      	    }
      	}
      }
      
      • 拆箱

      • 使用Convert类
        在这里插入图片描述

      • ToString方法与各数据类型的Parse/TryParse方法
        使用WPF窗体

      private void Btn_click(object sender, RoutedEventArgs e)
      {
          double x = System.Convert.ToDouble(tb1.Text);
          double y = System.Convert.ToDouble(tb2.Text);
          double result = x + y;
          //this.tb3.Text=System.Convert.ToString(result);    //使用Convert
          this.tb3.Text = result.ToString();  //直接使用ToString()
      }
      

      在这里插入图片描述
      Parse与TryParse

      private void Btn_click(object sender, RoutedEventArgs e)
      {
          double x = double.Parse(tb1.Text);
      	double y = double.Parse(tb2.Text);
      	double result = x + y;
      	this.tb3.Text = result.ToString();  //直接使用ToString()
      }
      

      注意输入格式的正确性
      在这里插入图片描述
      上面这种出不来结果

    • 自定义类型转换操作符示例
      本质是在被转换的类中创建方法
      特定的关键字
      隐式和显式的区别

    internal class Program
    {
        static void Main(string[] args)
        {
            Stone stone = new Stone();
            stone.Age = 5000;
            Monkey wukongSun = (Monkey)stone;
            //Monkey wukongSun = stone;   //隐式类型转换
            Console.WriteLine(wukongSun.Age);
        }
    }
    
    class Stone //如果里面不加任何操作,上面强制类型转换,无法转换
    {
        public int Age;
    
        //该实例创建在被转换的类里面
        public static explicit operator Monkey(Stone stone)
        //public static implicit operator Monkey(Stone stone) //隐式类型转换
        {
            Monkey m = new Monkey();
            m.Age = stone.Age / 500;
            return m;
        }
    }
    
    class Monkey
    {
        public int Age;
    }
    
  • +, -, “*”, /, %操作符

    • 留意数值提升,例如:int->double
    • 正无穷,负无穷,NaN等看文档
    • 操作的类型不同,进行不同的运算。例如:整数除法与浮点型除法
    • 正无穷与负无穷
    double x = 5.0;
    double y = 0;
    double z = x / y;  //+Infinity
    
    double x = -5.0;
    double y = 0;
    double z = x / y;  //-Infinity
    
    double x = double.PositiveInfinity;
    double y = double.NegativeInfinity;
    double z = x / y;  //NaN(Not a Number)
    
    • 加减法也会发生类型提升
    var x = 3.0 + 4;
    Console.WriteLine(x.GetType().Name);
    Console.WriteLine(x);
    
    • 加号连接字符串
    string s1 = "123";
    string s2 = "abc";
    string s3 = s1 + s2;
    Console.WriteLine(s3);  //123abc
    
  • 位移操作符 << 和 >>

    • 注意溢出的情况
    • 在没有溢出的情况下,左移就是乘2右移就是除2
    • 左移和右移的补位规则。左移不论是正数还是负数最高位都死补0,右移正数最高位补0,负数最高位补1
  • 关系操作符 > < >= <= == !=

    • 关系操作符的运算结果是布尔类型的
    • 可以比较字符类型与数据类型
    • 字符串只能比相等于不相等,不能比大小
    • 大写字母转小写字母库里面的方法:Tolower()
    string str1 = "abc";
    string str2 = "Abc";
    Console.WriteLine(str1.ToLower() == str2.ToLower());    //大写字母转成小写字母
    
  • 类型检验操作符is as

    • is操作符用来检验一个对象是不是某个类型的对象
    • 检验的不是变量而是变量所引用的实例
    • is与as的更多用法参考大佬文章:链接: link
  • 逻辑运算符& | ^ && ||

    • 基本用法简单
    • 使用&&和||时要注意:从左往右执行时后面的条件是否还会执行?(短路效应),注意避开这一特点
  • null合并操作符 ??

    • c#将Nullable关键字吸收为“ ?”
    //Nullable<int> x = null; //使用该关键字将null放入int类型当中
    int? x = null;
    Console.WriteLine(x);   //没东西
    Console.WriteLine(x.HasValue);  //False
    
    • ??引用实例介绍
    int? x = null;
    int y = x ?? 1; //第一个问号判断x是否为空,如果为空则赋值1
    Console.WriteLine(y);   //1
    
  • 其他操作符常规,不做笔记

出处链接: link

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值