您当前的位置: 首页 >  c#

蔗理苦

暂无认证

  • 4浏览

    0关注

    88博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

2022-04-17 C# 第3篇——核心

蔗理苦 发布时间:2022-04-17 03:40:54 ,浏览量:4

文章目录
        • 一、GC 回收机制
        • 二、成员属性
        • 三、索引器
        • 四、静态成员
        • 五、静态类和静态构造函数
        • 六、拓展方法
        • 七、运算符重载
        • 七、内部类和分部类
        • 八、继承
        • 九、里氏替换原则
        • 十、继承中的构造函数
        • 十一、万物之父和装箱拆箱
        • 十二、密封类
        • 十三、多态 vob
        • 十四、抽象类和抽象方法
        • 十五、接口
        • 十六、密封方法
        • 十七、命名空间
        • 十八、万物之父中的方法
        • 十九、string
        • 二十、StringBuilder
        • 二十一、结构体和类的区别
        • 二十二、抽象类和接口的区别

一、GC 回收机制

​ 垃圾回收,英文简写 GC(Garbage Collector) ​ 垃圾回收的过程是在遍历堆(Heap)上动态分配的所有对象,通过识别它们是否被引用来确定哪些对象是垃圾,哪些对象仍要被使用 ​ 所谓的垃圾就是没有被任何变量,对象引用的内容 ​ 垃圾就需要被回收释放

​ 垃圾回收有很多种算法,比如: ​ 引用计数(Reference Counting) ​ 标记清除(Mark Sweep) ​ 标记整理(Mark Compact) ​ 复制集合(Copy Collection)

​ 注意: ​ GC只负责堆(Heap)内存的垃圾回收 ​ 引用类型都是存在堆(Heap)中的,所以它的分配和释放都通过垃圾回收机制来管理

​ 栈(Stack)上的内存是由系统自动管理的 ​ 值类型在栈(Stack)中分配内存的,他们有自己的生命周期,不用对他们进行管理,会自动分配和释放

​ C# 中内存回收机制的大概原理 ​ 0代内存 1代内存 2代内存 ​ 代的概念: ​ 代是垃圾回收机制使用的一种算法(分代算法) ​ 新分配的对象都会被配置在第0代内存中 ​ 每次分配都可能会进行垃圾回收以释放内存(0代内存满时)

​ 在一次内存回收过程开始时,垃圾回收器会认为堆中全是垃圾,会进行以下两步 ​ 1.标记对象 从根(静态字段、方法参数)开始检查引用对象,标记后为可达对象,未标记为不可达对象,不可达对象就认为是垃圾 ​ 2.搬迁对象压缩堆 (挂起执行托管代码线程) 释放未标记的对象 搬迁可达对象 修改引用地址

​ 大对象总被认为是第二代内存 目的是减少性能损耗,提高性能 ​ 不会对大对象进行搬迁压缩 85000字节(83kb)以上的对象为大对象

二、成员属性

​ 基本概念

  1. 用于保护成员变量

  2. 为成员属性的获取和赋值添加逻辑处理

  3. 解决 3P (Private、Public、Protected)的局限性

    public——内外访问

    private——内部访问

    protected——内部和子类访问

​ 属性可以让成员变量在外部只能获取、不能修改,或者,只能修改、不能获取

// 访问修饰符 属性类型 属性名            
// {                         
//     get{}                 
//     set{}                 
// }         

internal class Person
{
    private int age;
    private int money;

    // 属性的命名一般使用 帕斯卡命名法
    public string Name { get; set; }

    public int Money {
        get =>
            //解密处理
            money - 5;
        set =>
            //加密处理
            money = value + 5;
    }

    // get和set可以只有一个

    // 注意:
    // 只有一个时  没必要在前面加访问修饰符
    // 一般情况下 只会出现 只有 get的情况 基本不会出现只有set
    public bool Sex { get; }
    // set
    // {
    //     sex = value;
    // }

    // 作用:外部能得不能改的特征
    // 如果类中有一个特征是只希望外部能得不能改的 又没什么特殊处理
    // 那么可以直接使用自动属性
    public float Height {
        // 没有再get和set中写逻辑的需求或者想法
        get;
        private set;
    }

    // 成员属性中,get和set前可以加访问修饰符

    // 注意
    // 1.默认不加 会使用属性申明时的访问权限
    // 2.加的访问修饰符要低于属性的访问权限
    // 3.不能让get和set的访问权限都低于属性的权限
}                              

​ 1、成员属性概念:一般是用来保护成员变量的 ​ 2、成员属性的使用和变量一样 外部用对象点出 ​ 3、get 中需要 return 内容 ; set 中用 value 表示传入的内容 ​ 4、get 和 set 语句块中可以加逻辑处理 ​ 5、get 和 set 可以加访问修饰符,但是要按照一定的规则进行添加 ​ 6、get 和 set 可以只有一个 ​ 7、自动属性是属性语句块中只有 get 和 set,一般用于 外部能得不能改这种情况

三、索引器

​ 索引器:让对象可以像数组一样通过索引访问其中元素,使程序看起来更直观,更容易编写

// 访问修饰符 返回值 this[参数类型 参数名, 参数类型 参数名.....]
// {
//       内部的写法和规则和属性相同
//       get{}
//       set{}
// }

internal class Person
{
    private int age;

    private int[,]   array;
    private Person[] friends;
    private string   name;

    public Person this[int index] {
        get {
            // 可以写逻辑的 根据需求来处理这里面的内容
            // 索引器中可以写逻辑
            if (friends == null ||
                friends.Length - 1  friends.Length - 1)
                // 自己定了一个规则 如果索引越界 就默认把最后一个朋友顶掉
                friends[friends.Length - 1] = value;
            friends[index] = value;
        }
    }

    // 索引器可以重载

    // 重载的概念是——函数名相同 参数类型、数量、顺序不同
    public int this[int i, int j] {
        get => array[i, j];
        set => array[i, j] = value;
    }

    public string this[string str] {
        get {
            switch (str)
            {
                case "name":
                    return name;
                case "age":
                    return age.ToString();
            }

            return "";
        }
    }
}

​ 注意:结构体里面也支持索引器

四、静态成员

​ 概念:用 static 修饰的成员变量、成员方法、成员属性等 就称为静态成员 ​ 特点:直接用类名点出来使用(全局性) ​ 生命周期:和程序同生共死 ​ 程序运行后就会一直存在内存中,知道程序结束后才会释放,因此静态成员具有唯一性 ​ 注意: ​ 1、静态函数中不能直接使用非静态成员 ​ 2、非静态函数中可以直接使用静态成员

​ 常量和静态变量 ​ 常量是特殊的静态变量 ​ 相同点: ​ 他们都可以通过类名点出来使用 ​ 不同点: ​ 1、const 必须初始化不能被修改 static 没有这个规则 ​ 2、const 只能修饰变量,static 可以修饰很多 ​ 3、const 不能写在访问修饰符前面,一定是写在变量申明前面 static 没有这个规则

五、静态类和静态构造函数

(一)静态类

​ 概念:用 static 修饰的类

​ 特点:

​ 1、只能包含静态成员

​ 2、不能被实例化

​ 作用:

​ 1、将常用的静态成员写在静态类中,方便使用

​ 2、静态类不能被实例化,更能体现工具类的唯一性 ​ 比如 Console 就是一个静态类

(二)静态构造函数

​ 概念:在构造函数加上 static 修饰

​ 特点: ​ 1、静态类和普通类都可以有

​ 2、不能使用访问修饰符

​ 3、不能有参数

​ 4、只会自动调用一次

​ 作用:在静态构造函数中初始化静态变量

// 1.静态类中的静态构造函数                           
internal static class StaticClass         
{                                         
    public static int testInt  = 100;     
    public static int testInt2 = 100;     
                                          
    static StaticClass()                  
    {                                     
        Console.WriteLine("静态构造函数");      
        testInt  = 200;                   
        testInt2 = 300;                   
    }                                     
}                                         
                                          
// 2.普通类中的静态构造函数                           
internal class Test                       
{                                         
    public static int testInt = 200;      
                                          
    static Test()                         
    {                                     
        Console.WriteLine("静态构造");        
    }                                     
                                          
    public Test()                         
    {                                     
        Console.WriteLine("普通构造");        
    }                                     
}                                         
六、拓展方法

​ 概念:为现有非静态变量类型添加新方法 ​ 作用: ​ 1、提升程序拓展性 ​ 2、不需要再对象中重新写方法 ​ 3、不需要继承来添加方法 ​ 4、为别人封装的类型写额外的方法 ​ 特点: ​ 1、一定是写在静态类中 ​ 2、一定是个静态函数 ​ 3、第一个参数为拓展目标 ​ 4、第一个参数用 this 修饰

​ 语法:

访问修饰符 static 返回值 函数名(this 拓展类名 参数名, 参数类型 参数名,参数类型 参数名....)

七、运算符重载

​ 概念:让自定义类和结构体能够使用运算符

​ 使用关键字 operator

​ 特点: ​ 1、一定是一个公共的静态方法 ​ 2、返回值写在 operator 前 ​ 3、逻辑处理自定义

​ 作用:让自定义类和结构体对象可以进行运算 ​ 注意: ​ 1、条件运算符需要成对实现 ​ 2、一个符号可以多个重载 ​ 3、不能使用 ref 和 out

​ 基本语法:

public static 返回类型 operator 运算符(参数列表)

internal class Point                                             
{                                                                
    public int x;                                                
    public int y;                                                
                                                                 
    public static Point operator +(Point p1, Point p2)           
    {                                                            
        var p = new Point();                                     
        p.x = p1.x + p2.x;                                       
        p.y = p1.y + p2.y;                                       
        return p;                                                
    }                                                            
                                                                 
    public static Point operator +(Point p1, int value)          
    {                                                            
        var p = new Point();                                     
        p.x = p1.x + value;                                      
        p.y = p1.y + value;                                      
        return p;                                                
    }                                                            
                                                                 
    public static Point operator +(int value, Point p1)          
    {                                                            
        var p = new Point();                                     
        p.x = p1.x + value;                                      
        p.y = p1.y + value;                                      
        return p;                                                
    }                                                                       
                                                                 
    // 注意 符号需要两个参数还是一个参数                                          
    public static Point operator -(Point p1, Point P2)           
    {                                                            
        return null;                                             
    }                                                            
                                                                 
    public static Point operator *(Point p1, Point P2)           
    {                                                            
        return null;                                             
    }                                                            
                                                                 
    public static Point operator /(Point p1, Point P2)           
    {                                                            
        return null;                                             
    }                                                            
                                                                 
    public static Point operator %(Point p1, Point P2)           
    {                                                            
        return null;                                             
    }                                                            
                                                                 
    public static Point operator ++(Point p1)                    
    {                                                            
        return null;                                             
    }                                                            
                                                                 
    public static Point operator --(Point p1)                    
    {                                                            
        return null;                                             
    }                                                            
                                                                   
    // 注意 符号需要两个参数还是一个参数                                          
    public static bool operator !(Point p1)                      
    {                                                            
        return false;                                            
    }                                                                      
                                                                 
    // 注意 符号需要两个参数还是一个参数                                          
    public static Point operator |(Point p1, Point p2)           
    {                                                            
        return null;                                             
    }                                                            
                                                                 
    public static Point operator &(Point p1, Point p2)           
    {                                                            
        return null;                                             
    }                                                            
                                                                 
    public static Point operator ^(Point p1, Point p2)           
    {                                                            
        return null;                                             
    }                                                            
                                                                 
    public static Point operator ~(Point p1)                     
    {                                                            
        return null;                                             
    }                                                            
                                                                 
    public static Point operator  (Point p1, int num)          
    {                                                            
        return null;                                             
    }                                                                  
                                                                 
    // 1.返回值一般是 bool 值 也可以是其它的                                      
    // 2.相关符号必须配对实现                                               
    public static bool operator >(Point p1, Point p2)            
    {                                                            
        return false;                                            
    }                                                            
                                                                 
    public static bool operator =(Point p1, Point p2)           
    {                                                            
        return false;                                            
    }                                                            
                                                                 
    public static bool operator 。。。——>子类构造
internal class GameObject
{
    public GameObject()
    {
        Console.WriteLine("GameObject的构造函数");
    }
}

internal class Player : GameObject
{
    public Player()
    {
        Console.WriteLine("Player的构造函数");
    }
}

internal class MainPlayer : Player
{
    public MainPlayer()
    {
        Console.WriteLine("MainPlayer的构造函数");
    }
}

// 父类的无参构造函重要
// 子类实例化时 默认自动调用的 是父类的无参构造 所以如果父类无参构造被顶掉 会报错
internal class Father
{
    // public Father()
    // {

    // }

    public Father(int i)
    {
        Console.WriteLine("Father构造");
    }
}

internal class Son : Father
{
    // 通过base调用指定父类构造

    public Son(int i) : base(i)
    {
        Console.WriteLine("Son的一个参数的构造");
    }

    public Son(int i, string str) : this(i)
    {
        Console.WriteLine("Son的两个参数的构造");
    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        Console.WriteLine("继承中的构造函数");

        var mp = new MainPlayer();

        var s = new Son(1, "123");
    }
}

​ 特点:执行顺序 是先执行父类的构造函数 再执行子类的 从老祖宗开始 依次一代一代向下执行

​ 父类中的无参构造函数很重要,如果被顶掉 子类中就无法默认调用无参构造了 ​ 解决方法: ​ 1、始终保持申明一个无参构造 ​ 2、通过 base 关键字,调用指定父类的构造 ​ 注意: ​ 区分 this 和 base 的区别

十一、万物之父和装箱拆箱

(一)万物之父

​ 关键字:object ​ 概念:object 是所有类型的基类,它是一个类(引用类型) ​ 作用: ​ 1、可以利用里氏替换原则,用 object 容器装所有对象 ​ 2、可以用来表示不确定类型,作为函数参数类型

(二)装箱拆箱

​ 发生条件:用 object 存值类型(装箱),再把 object 转为值类型(拆箱)

​ 装箱:把值类型用引用类型存储,栈内存会迁移到堆内存中

​ 拆箱:把引用类型存储的值类型取出来,堆内存会迁移到栈内存中

​ 好处:不确定类型时可以方便参数的存储和传递 ​ 坏处:存在内存迁移,增加性能消耗

// 装箱                  
object v = 3;   

// 拆箱                  
var intValue = (int) v;
十二、密封类

​ 使用 sealed 密封关键字修饰的类 ​ 作用:让类无法再被继承

​ 意义:加强面向对象程序设计的规范性、结构性、安全性

十三、多态 vob

(一)多态的概念

​ 多态按字面的意思就是“多种状态” ​ 让继承同一父类的子类们 在执行相同方法时有不同的表现(状态) ​ 主要目的:同一父类的对象 执行相同行为(方法)有不同的表现 ​ 解决的问题:让同一个对象有唯一行为的特征

(二)vob 的使用

// 运行时多态( vob、抽象函数、接口 )                                               
// v: virtual(虚函数)                                            
// o: override(重写)                                            
// b: base(父类)                                                
                                                             
internal class GameObject                                    
{                                                            
    public string name;                                      
                                                             
    public GameObject(string name)                           
    {                                                        
        this.name = name;                                    
    }                                                        
                                                             
    // 虚函数 可以被子类重写                                            
    public virtual void Atk()                                
    {                                                        
        Console.WriteLine("游戏对象进行攻击");                       
    }                                                        
}                                                            
                                                             
internal class Player : GameObject                           
{                                                            
    public Player(string name) : base(name) { }              
                                                             
    // 重写虚函数                                                  
    public override void Atk()                               
    {                                                        
        // base 的作用                                            
        // 代表父类 可以通过base来保留父类的行为                              
        base.Atk();                                          
        Console.WriteLine("玩家对象进行攻击");                       
    }                                                        
}                                                            
                                                             
internal class Monster : GameObject                          
{                                                            
    public Monster(string name) : base(name) { }             
                                                             
    public override void Atk()                               
    {                                                        
        Console.WriteLine("怪物对象进行攻击");                       
    }                                                        
}                                                                
                                                             
internal class Program                                       
{                                                            
    private static void Main(string[] args)                  
    {                                                        
        Console.WriteLine("多态vob");                                        
                                                             
        Father f = new Son();                                
        f.SpeakName();                                       
        (f as Son).SpeakName();                                      
                                                             
        // 多态的使用                                             
        GameObject p = new Player("xxx");                    
        p.Atk();                                             
        (p as Player).Atk();                                 
                                                             
        GameObject m = new Monster("xxx");                   
        m.Atk();                                             
        (m as Monster).Atk();                                     
    }                                                        
}                                                            

​ 多态:让同一类型的对象,执行相同行为时有 ​ 解决的问题: 让同一对象有唯一的行为特征 ​ vob: ​ v:virtual 虚函数 ​ o:override 重写 ​ b:base 父类 v 和 o 一定是结合使用的,来实现多态 b 是否使用根据实际需求,保留父类行为

十四、抽象类和抽象方法

(一)抽象类

​ 概念:被抽象关键字abstract修饰的类 ​ 特点: ​ 1、不能被实例化的类 ​ 2、可以包含抽象方法 ​ 3、继承抽象类必须重写其抽象方法

(二)抽象方法

​ 又叫纯虚方法,用 abstract 关键字修饰的方法 ​ 特点: ​ 1、只能在抽象类中申明 ​ 2、没有方法体 ​ 3、不能是私有的 ​ 4、继承后必须实现,用 override 重写

internal abstract class Fruits                    
{                                                 
    public string name;                           
                                                  
    // 抽象方法 是一定不能有函数体的                             
    public abstract void Bad();                   
                                                  
    public virtual void Test()                    
    {                                             
        // 可以选择是否写逻辑                               
    }                                             
}                                                 
                                                  
internal class Apple : Fruits                     
{                                                 
    public override void Bad() { }                
    // 虚方法是可以由我们子类选择性来实现的                          
    // 抽象方法必须要实现                                   
}                                                 
                                                  
internal class SuperApple : Apple                 
{                                                 
    // 虚方法和抽象方法 都可以被子类无限的 去重写                      
    public override void Bad()                    
    {                                             
        base.Bad();                               
    }                                             
                                                  
    public override void Test()                   
    {                                             
        base.Test();                              
    }                                             
}

internal class Program                      
{                                           
    private static void Main(string[] args) 
    {                                       
        Console.WriteLine("抽象类和抽象方法");      
        // 抽象不能被实例化                          
        // Thing t = new Thing();            
        // 但是 可以遵循里氏替换原则 用父类容器装子类            
        Thing t = new Water();              
    }                                       
}                                           
十五、接口

​ 接口是行为的抽象规范,它也是一种自定义类型 ​ 关键字 :interface

​ 接口申明的规范 ​ 1、不包含成员变量 ​ 2、只包含方法、属性、索引器、事件 ​ 3、成员不能被实现 ​ 4、成员可以不用写访问修饰符,不能是私有的 ​ 5、接口不能继承类,但是可以继承另一个接口

​ 接口的使用规范 ​ 1、类可以继承多个接口 ​ 2、类继承接口后,必须实现接口中所有成员

​ 特点: ​ 1、它和类的申明类似 ​ 2、接口是用来继承的 ​ 3、接口不能被实例化,但是可以作为容器存储对象

// 接口关键字:interface                                    
// 语法:                                                
// interface 接口名                                     
// {                                                 
// }                                                 
// 一句话记忆:接口是抽象行为的“基类”                                 
// 接口命名规范 帕斯卡前面加个 I                                    
                                                     
internal interface IFly                              
{                                                    
    string Name { get; set; }                        
                                                     
    int this[int index] { get; set; }                
                                                     
    void Fly();                                      
                                                     
    event Action doSomthing;                         
}                                                             
                                                     
// 接口用来继承                                             
internal class Animal { }                            
                                                     
// 1.类可以继承1个类,n个接口                                    
// 2.继承了接口后 必须实现其中的内容 并且必须是public的                    
internal class Person : Animal, IFly                 
{                                                    
    // 3.实现的接口函数,可以加virtual再在子类重写                           
    public virtual void Fly() { }                    
                                                     
    public string Name { get; set; }                 
                                                     
    public int this[int index] {                     
        get => 0;                                    
        set { }                                      
    }                                                
                                                     
    public event Action doSomthing;                  
}                                                    
                                                     
// 接口可以继承接口                                                                              
// 接口继承接口时  不需要实现                                     
// 待类继承接口后  类自己去实现所有内容                                
internal interface IWalk                             
{                                                    
    void Walk();                                     
}                                                    
                                                     
internal interface IMove : IFly, IWalk { }           
                                                     
internal class Test : IMove                          
{                                                    
    public int this[int index] {                     
        get => throw new NotImplementedException();  
        set => throw new NotImplementedException();  
    }                                                
                                                     
    public string Name {                             
        get => throw new NotImplementedException();  
        set => throw new NotImplementedException();  
    }                                                
                                                     
    public event Action doSomthing;                  
                                                     
    public void Fly()                                
    {                                                
        throw new NotImplementedException();         
    }                                                
                                                     
    public void Walk()                               
    {                                                
        throw new NotImplementedException();         
    }                                                
}                                                                                     
                                                     
// 当一个类继承两个接口                                         
// 但是接口中存在着同名方法时                                      
// 注意:显示实现接口时 不能写访问修饰符                                           
internal interface IAtk                              
{                                                    
    void Atk();                                      
}                                                    
                                                     
internal interface ISuperAtk                         
{                                                    
    void Atk();                                      
}                                                    
                                                     
internal class Player : IAtk, ISuperAtk              
{                                                    
    // 显示实现接口 就是用 接口名.行为名 去实现                         
    void IAtk.Atk() { }                              
                                                     
    void ISuperAtk.Atk() { }                         
                                                     
    public void Atk() { }                            
}                                                      
                                                     
internal class Program                               
{                                                    
    private static void Main(string[] args)          
    {                                                
        Console.WriteLine("接口");                     
        // 4.接口也遵循里氏替换原则                              
        IFly f = new Person();                       
                                                     
        IMove im   = new Test();                     
        IFly  ifly = new Test();                     
        IWalk iw   = new Test();                     
                                                     
        IAtk      ia  = new Player();                
        ISuperAtk isa = new Player();                
        ia.Atk();                                    
        isa.Atk();                                   
                                                     
        var p = new Player();                        
        (p as IAtk).Atk();                           
        (p as ISuperAtk).Atk();                      
        p.Atk();                                     
    }                                                
}                                                    
十六、密封方法

​ 用密封关键字 sealed 修饰的重写函数 ​ 作用:让虚方法或者抽象方法之后不能再被重写 ​ 特点:和 override 一起出现

十七、命名空间

​ 概念:命名空间是用来组织和重用代码的 ​ 作用:就像是一个工具包,类就像是一件一件的工具,都是申明在命名空间中的

// 基本语法                                             
// namespace 命名空间名                                  
// {                                                
//     类                                              
//     类                                              
// }                                                
namespace MyGame                                   
{                                                  
    internal class GameObject { }                  
}                                                  
                                                   
namespace MyGame                                   
{                                                  
    internal class Player : GameObject { }         
}                                                  

// 不同命名空间中允许有同名类                                                                            
namespace MyGame2                                  
{                                                  
    // 在不同的命名空间中 是可以有同名类的                           
    internal class GameObject { }                  
}                                                  
                                                   
// 命名空间可以包裹命名空间                                                 
namespace MyGame                                   
{                                                  
    namespace UI                                   
    {                                              
        internal class Image { }                   
    }                                              
                                                   
    namespace Game                                 
    {                                              
        internal class Image { }                   
    }                                              
}                                                  
十八、万物之父中的方法

(一)静态方法

  1. public static bool Equals(object? objA, object? objB);
// 静态方法 Equals 判断两个对象是否相等
// 最终的判断权,交给左侧对象的Equals方法,
// 不管值类型引用类型都会按照左侧对象Equals方法的规则来进行比较
Console.WriteLine(Equals(1, 1));          
Test t = new Test();                    
Test t2 = new Test();                   
Console.WriteLine(Object.Equals(t, t2));
  1. public static bool ReferenceEquals(object? objA, object? objB);
// 静态方法 ReferenceEquals             
// 比较两个对象是否是相同的引用,主要是用来比较引用类型的对象。  
// 值类型对象返回值始终是false。               
Console.WriteLine(Object.ReferenceEquals(t, t2));

(二)成员方法

  1. public Type GetType();
// 普通方法GetType                                
// 该方法在反射相关知识点中是非常重要的方法,之后我们会具体的讲解这里返回的Type类型。
// 该方法的主要作用就是获取对象运行时的类型Type,                  
// 通过Type结合反射相关知识点可以做很多关于对象的操作。               
var t    = new Test();                       
var type = t.GetType();                      
  1. protected object MemberwiseClone ();
// 普通方法 MemberwiseClone               
// 该方法用于获取对象的浅拷贝对象,口语化的意思就是会返回一个新的对象,
// 但是新对象中的引用变量会和老对象中一致。              
var t2 = t.MemberwiseClone();                 

(三)虚方法

  1. public virtual bool Equals(object? obj);
// 虚方法Equals                                    
// 默认实现还是比较两者是否为同一个引用,即相当于ReferenceEquals。      
// 但是微软在所有值类型的基类System.ValueType中重写了该方法,用来比较值相等。
// 我们也可以重写该方法,定义自己的比较相等的规则                      
  1. public virtual int GetHashCode();
// 虚方法GetHashCode                                 
// 该方法是获取对象的哈希码                                   
// (一种通过算法算出的,表示对象的唯一编码,不同对象哈希码有可能一样,具体值根据哈希算法决定),
// 我们可以通过重写该函数来自己定义对象的哈希码算法,正常情况下,我们使用的极少,基本不用。   
  1. public virtual string? ToString();
// 虚方法ToString                                     
// 该方法用于返回当前对象代表的字符串,我们可以重写它定义我们自己的对象转字符串规则,       
// 该方法非常常用。当我们调用打印方法时,默认使用的就是对象的ToString方法后打印出来的内容。
Console.WriteLine(t);
十九、string
// 1.字符串指定位置获取

// 字符串本质是char数组                                                                      
var str = "xxx";                                                                    
Console.WriteLine(str[0]);                                                          
// 转为char数组                                                                          
var chars = str.ToCharArray();                                                      
Console.WriteLine(chars[1]);
for (var i = 0; i             
关注
打赏
1657823434
查看更多评论
0.1093s