初学者最细的C#基础

本文介绍了C#中的访问修饰符,如public、private等,以及方法的作用、分类和参数传递方式,包括值参数、引用参数和输出参数。还讲解了数组的使用,包括一维、多维和交错数组,以及Array类的属性和方法。此外,文章还涉及字符串操作,如格式化输出、时间格式化以及StringBuilder类。最后,讨论了面向对象的封装、继承和多态的概念。
摘要由CSDN通过智能技术生成

c#基础4

随风1987

已于 2023-06-07 15:24:22 修改

2
 收藏
文章标签: c# c++ 开发语言
版权
1.访问修饰符
作用
所有类型和类型成员都具有可访问性级别.

分类
public : 同一程序集的其他任何代码或引用该程序集的其他程序集都可以访问该类型或成员。
internal : 同一程序集中的任何代码都可以访问该类型或成员,但其他程序集不可以访问。
private : 同一类和结构的代码可以访问该类型和成员。
protected : 同一类和派生(继承特性)类中的代码可以访问该类型和成员。
protected internal :  同一程序集中的任何代码或其他程序集中的任何派生类都可以访问该类型或成员。
private protected:该类型或成员可以通过从 class 派生的类型访问

C#的默认修饰符
    类、结构体的默认修饰符是internal。
    类中所有的成员默认修饰符是private。
    接口默认修饰符是internal。
    接口的成员默认修饰符是public。
    枚举类型成员默认修饰符是public。
    委托的默认修饰符是internal。

  2.C# 方法(函数)
 
作用:
    方法是包含一系列语句的代码块。方法必须在类或结构中声明

优点:
减少代码重复率

方法体现了c#语言的封装性

方法的分为 声明方法 和调用方法
声明方法基本结构:
    访问权限  返回值类型   代表方法 是否具有 return 数据的类型

       void  和 其他明确的数据类型 (int  float 。。 string。。。)
    方法名称     大驼峰   见名之意
    方法参数    实参(调用方法) 和形参(声明方法)
    括号{     

     语句块

    }
   调用方法:
     在哪调用(在方法内部调用    Main 入口方法  程序运行时 自动执行   Main方法是静态方法   自定义静态方法直接使用, 自定义非静态方法 需要对象打点调用)

  

  方法的分类:
   从访问权限分类
  从有无参数和有无返回值分类
  从静态和非静态分类

  参数传递 形式:
  值参数:

   特点:

  1.参数传递的默认方式 

  2.当调用一个方法时,会为每个值参数创建一个新的存储位置。

  3.当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全

  总结:无论参数的类型是值类型还是引用类型  都遵循值传递的特性

  引用参数 

   特点:

   1.引用参数是一个对变量的内存位置的引用 不会创建一个新的存储位置

   2. 参数关键字 ref

  

 int a = 10;
            int b = 20;
            Program  program = new Program();
            program.swap( ref a,ref b);
            Console.WriteLine("调用方法后a的值{0}",a);
            Console.WriteLine("调用方法后b的值{0}",b);
 
 
            string stra = "123";
            string strb = "456";
            program.swapString(ref stra,ref strb);
            Console.WriteLine("调用方法后 stra的值{0}", stra);
            Console.WriteLine("调用方法后strb的值{0}", strb);
 
            int[] intArray1 = new int[] { 1, 2 };
            int[] intArray2 = new int[] { 3, 4 };
 
            program.swapIntArray(ref intArray1,ref intArray2);
            foreach (int i in intArray1)
            {
                Console.WriteLine(i);
            }
 
            foreach (int i in intArray2)
            {
                Console.WriteLine(i);
            }
 
            People people = new People() { Id = 1000 };
            People people1 = new People() { Id = 2000 };
            program.swapPeople(ref people, ref people1);
            Console.WriteLine(people.Id);
            Console.WriteLine(people1.Id);

输出参数

  特点:

1. 是对于方法返回值的补充。return 语句可用于函数中返回一个值  输出参数可以返回多个值

2.关键字 out    out输出参数在方法中 必须被使用,且和retrun保持一致

3. 其他方面与引用参数相似

可变参数params (讲完数组再说)
1.params是ParamArrayAttribute(参数数组属性)的缩写
2.param解决了C#中不定参数的传递的问题

3.params参数必须定义在参数列表最后面。
   4.params必须对一维数组描述
     5.params只能在一个方法中 定义一个一维数组

static void ParamtesDemo(string className, params string[] names)
        {
               string tempStr = "";
              foreach (string name in names)
               {
                    tempStr += name;  
               }
                Console.WriteLine($"{className}的学生有:{tempStr}");
         }
ParamtesDemo("223班级", "张三", "李四", "王五", "赵六");


C# 空类型(Null)
1.Null
特点:

1.表示不引用任何对象的空引用,没有创建内存空间,存放的是空引用指针;

2.Null类型是System.Nullable<T>这个struct的类型

3.对于值类型 赋值不能直接为null    引用类型可以

4.null引用类型变量的默认值

值类型如何赋值为null?

1.Nullable<T>结构体

Nullable<int> intNumber = null;


2.类型之后添加 单 ?

int? intNumber = null;


使用场景:

当我们想要对于一个值类型变量进行 判断 是否 存在时,为了节约内存 可以赋值为null

null和字符串空值和字符串空格的区别
1.null是没有创建内存空间,

2.字符串空值  为"" 或者string.Empty  实际上都会分配空间;

3.字符串空格 "    "  会分配空间 空格也是ACSII  对应的符号

     

      string str = "123"; //正常字符串,有值非空
            string str1 = null;  //值为null
            string str2 = "";    //是个空字符串
            string str3 = "    ";//空白字符串,双引号之间是空格或者Tab键
            Console.WriteLine(string.IsInterned(str));
            Console.WriteLine(string.IsInterned(str1));
            Console.WriteLine(string.IsInterned(str2));
            Console.WriteLine(string.IsInterned(str3));


 
 
             IsInterned方法 判断数据是否已经存在于内存中
 双问号 ??(合并运算符)
作用:

用于判断一个变量在为 null 的时候返回一个指定的值

使用场景

Null 合并运算符为类型转换定义了一个预设值,以防可空类型的值为 Null

       

         double? num1 = null;
         double? num2 = 3.14157;
         double num3;
         num3 = num1 ?? 5.34;      // num1 如果为空值则返回 5.34
         Console.WriteLine("num3 的值: {0}", num3);
         num3 = num2 ?? 5.34;
         Console.WriteLine("num3 的值: {0}", num3);


不可变数组
含义:
不可变数组是一个存储相同类型元素的固定大小的顺序集合

特点:

数组属于引用类型

数组只能包含类型相同的元素

数组通过下标(索引值)标记元素

格式:
声明数组:

datatype[] arrayName;

datatype 用于指定被存储在数组中的元素的类型。
指定数组的秩(维度)。秩指定数组的大小。
arrayName 指定数组的名称。
初始化数组中的元素的方式

数据类型[] 数组名 = new 数据类型[长度];
数据类型[] 数组名 = {值 1, 值 2, …}
数据类型[] 数组名 = new 数据类型[长度]{值 1,值 2,…}

数据类型[] 数组名 = new 数据类型[长度可忽略]{值 1,值 2,…}

数组访问元素:
修改数组元素:
遍历数组方式:
for

foreach

数组越界
例子:在控制台中录入学生成绩

要求:成绩范围0–100
“请输入学生总数:”
“请输入学生成绩:”
"输入的成绩有误 : "

多维数组
含义:数组嵌套数组形式   一般常用二维数组

二位数组格式:string [,] strArray =new string[数组个数,数组元素个数]

初始化二维数组

 /* 一个带有 5 行 2 列的数组 */
            int[,] a = new int[5, 2] {{0,0}, {1,2}, {2,4}, {3,6}, {4,8} };


二维数组访问元素:
  int val = a[2,3];

二维数组修改元素:
a[2,3]=10;

遍历二维数组元素
   

  for (int i = 0; i < studentArray.GetLength(0); i++) {
 
                for (int j = 0; j < studentArray.GetLength(1);j++) {
 
                    Console.WriteLine(studentArray[i, j]);
                }
                
            }

其他多维数组格式: 例如三维数组 string [,,] strArray =new string[数组个数,数组元素个数]
int[,,] val = new int[3, 3, 3]    { { { 10, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } },

                          { { 10, 11, 12 }, { 13, 14, 15 }, { 16, 17, 18 } },

{ { 19, 20, 21 }, {22, 23, 24 }, { 25, 26, 27 } } };

三维数组访问元素:
  int val = a[2,2,2];

三维数组修改元素:
a[2,2,2]=10;

遍历三维数组元素

  int[,,] tempArray = new int[2, 2, 2] { { {1,2 },{3,4 } },{ {5,6 },{7,8 } } };
 
            for (int i = 0; i < tempArray.GetLength(0); i++)
            {
 
                for (int j = 0; j < tempArray.GetLength(1); j++)
                {
 
                    for (int k = 0; k < tempArray.GetLength(2); k++) {
                        Console.WriteLine(tempArray[i,j,k]);
 
                    }
                 
                }
 
            }

交错数组 了解
含义
交错数组是数组的数组,交错数组是一维数组。

交错数组格式:

int [][] scores;


初始化交错数组中的元素的方式

    int[][] scores = new int[2][]{new int[]{92,93,94},new int[]{85,66,87,88}};

交错数组访问元素:
scores[0][1]

交错修改数组元素:
scores[0][1]  =10;

例子:在控制台中录入学生姓名 年龄 分数 性别
要求:成绩范围0–100  年龄要求18-20   性别要求 0对应女和 1 对应男
“请输入学生总数:

 添加学生姓名

展示所有学生信息

提示退出程序 或者是修改学生信息(Y/X)

提示修改第几个学生信息(一种有几个学生)?请输入对应的编号(1,2,3,4)

修改学生姓名

。。。。。

展示所有学生信息

提示退出程序 或者是修改学生信息(Y/X)

Array 类
含义:
是 C# 中所有数组的基类,它是在 System 命名空间中定义  提供了各种用于数组的属性和方法

常用属性 和方法

CreateInstance(typeof(int), 5);  //创建一维数组

 Array aa=       Array.CreateInstance(typeof(int), 5);
  aa.SetValue(0, 1);
  aa.GetValue(0);

   Array asa  =Array.CreateInstance(typeof(int), 2,2);//创建二维数组
    asa.SetValue(0, 1);

    asa.SetValue(0, 2)

     asa.SetValue(1, 2);

     asa.GetValue(1, 1);

Indexof(Array array, Obejct)    返回第一次出现的下标
Sort(Array array)    从小到大排序 (仅支持一维数组)
Reverse(Array array)    数组逆置
Clear(Array array, int index, int length)    将某个范围内的所有元素设为初始值
Copy      深复制   数组内容到另一个数组

//作业:1.写 四和5维数组  并且遍历   2.学生信息表 3.实现 sort  reverse  indexof 原理

格式化字符串方式
+拼接

            string name = "可乐";
            int age = 3;
            Console.WriteLine(name+age);        


         
占位符

            string name = "可乐";
            int age = 3;
            Console.WriteLine("{0}今年{1}岁",name,age);       


含义:用{ }来表示,在{ }内填写所占的位的序号,从0开始

格式化标识符
字母 含义
C或c Currency 货币格式
D或d Decimal 十进制格式(十进制整数,不要和.Net的Decimal数据类型混淆了)
E或e Exponent 指数格式
F或f Fixed point 固定精度格式
G或g General 常用格式
N或n 用逗号分割千位的数字,比如1234将会被变成1,234
P或p Percentage 百分符号格式
R或r Round-trip 圆整(只用于浮点数)保证一个数字被转化成字符串以后可以再被转回成同样的数字
X或x Hex 16进制格式
static void Main()   
         {
                   int i=12345;
                   Console.WriteLine("{0:C}",i);   //货币
                   Console.WriteLine("{0:D}",i);   //十进制数
                   Console.WriteLine("{0:E}",i);    //科学技术法
                   Console.WriteLine("{0:F}",i);   // 浮点数表示法
                   Console.WriteLine("{0:G}",i);   //G或g General 常用格式
                   Console.WriteLine("{0:N}",i);   //N或n 用逗号分割千位的数字
 
                   精度控制标识控制了有效数字的个数或者十进制数小数的位数
                    例如{0:C5}   C 代表类型  5代表精度
    
                    Console.WriteLine("{0:C5}", i); // ¥123,456.00
                    Console.WriteLine("{0:D5}", i); // 123456
                    Console.WriteLine("{0:E5}", i); // 1.23456E+005
                    Console.WriteLine("{0:F5}", i); // 123456.00000
                    Console.WriteLine("{0:G5}", i); // 1.23456E5
                    Console.WriteLine("{0:N5}", i); // 123,456.00000
                    Console.WriteLine("{0:P5}", i); // 12,345,600.00000 %
                    Console.WriteLine("{0:X5}", i); // 1E240
            
         }
 
时间格式化符号
d MM/dd/yyyy ShortDatePattern(短日期模式)
D dddd,MMMM dd,yyyy LongDatePattern(长日期模式)
F dddd,MMMM dd,yyyy HH:mm Full date and time (long date and short time)(全日期和时间模式)
F dddd,MMMM dd,yyyy HH:mm:ss FullDateTimePattern (long date and long time)(长日期和长时间)
G MM/dd/yyyy HH:mm General (short date and short time)(通用模式,短日期和短时间)
G MM/dd/yyyy HH:mm:ss General (short date and long time)(通用模式,短日期和长时间)
M,M MMMM dd MonthDayPattern(月天模式)
r,R ddd,dd MMM yyyy,HH':'mm':'ss 'GMT' RFC1123Pattern (RFC1123模式)
S yyyy-MM-dd HH:mm:ss SortableDateTimePattern (conforms to ISO 8601) using local time(使用本地时间的可排序模式)
T HH:mm ShortTimePattern (短时间模式)
T HH:mm:ss LongTimePattern(长时间模式)
U yyyy-MM-dd HH:mm:ss UniversalSortable-DateTimePattern (conforms to ISO 8601) using universal time(通用可排序模式)
U dddd,MMMM dd,yyyy,HH:mm:ss UniversalSortable-DateTimePattern(通用可排序模式)
y,Y MMMM,yyyy YearMonthPattern(年月模式)
static void Main()   
         {
                   Console.WriteLine("{0:D}",DateTime.Now);   //输出到天
                   Console.WriteLine("{0:y}",DateTime.Now);   //输出到月
                   Console.WriteLine("{0:m}",DateTime.Now);    //取出是那个月
                   Console.WriteLine("{0:T}",DateTime.Now);   // 取长时间到秒
                   Console.WriteLine("{0:t}",DateTime.Now);   //取短时间到分
                   Console.WriteLine("{0:tt}",DateTime.Now);   //取出是上午还是下午     
            
         }

string.Fromat() 

          

  string name = "可乐";
            int age = 3;
            string.Format("{0}今年{1}岁",name,age");


模板字符串 $"{变量1},{变量2}"

       

    string name = "可乐";
            int age = 3;
            Console.WriteLine($"{name}今年{age}岁");


字符串
含义:

string,引用类型,string类型表示零或更多 Unicode 字符组成的序列,

string 是 .NET Framework 中 String 的别名。

字符串常用API

    1.Length 获取字符串的长度,即字符串中字符的个数.
    2.IndexOf 返回整数,得到指定的字符串在原字符串中第一次出现的位置.
    3.LastlndexOf 返回整数,得到指定的字符串在原字符串中最后一次出现的位置.

    4. StartsWith 返回布尔型的值,判断某个字符串是否以指定的字符串开头.
       
    5. EndsWith 返回布尔型的值,判断某个字符串是否以指定的字符串结尾.
       
    6. ToLower 返回一个新的字符串,将字符串中的大写字母转换成小写字母.
       
    7. ToUpper 返回一个新的字符串,将字符串中的小写字母转换成大写字母.
       
    8. Trim返回一个新的字符串,不带任何参数时表示将原字符串中前后的空格删除.
       
    9. Remove 返回一个新的字符串,将字符串中指定位置的字符串移除.
    10. TrimStart 返回一个新的字符串,将字符串中左侧的空格删除.
       
    11. TrimEnd 返回一个新的字符串,将字符串中右侧的空格删除。
       
    12. PadLeft 返回一个新的字符串,从字符串的左侧填充空格达到指定的字符串长度.
       
    13. PadRight 返回一个新的字符串,从字符串的右侧填充空格达到指定的字符串长度.
       
    14. Substring 返回一个新的字符串,用于截取指定的字符串.
       
    15. Insert 返回一个新的字符串,将一个字符串插入到另一个字符串中指定索引的位置.
        

StringBuilder类的使用                 

特点:

1.可以定义可变字符串,实现字符串的添加

2.对于高频率字符串拼接可以使用

3.如果普通拼接 可以使用上节课所以将的字符串格式化方式

常用方法如下:

Append  末尾追加

Insert 在指定位置插入指定字符串

Remover 移除指定字符串

         

//普通拼接方法  (低效率 会频繁开辟不连续的内存空间 )
            string str = string.Empty;
            str += "abc";
            str += "efg";
 
 
            //(高效率 StringBuilder(可变字符串)在创建后 追加新的内容 是在原有内存中连续创建 提高效率)
            StringBuilder sb = new StringBuilder();
            //追加
            sb.Append("你好");
            sb.Append("吃饭了么");
            Console.WriteLine(sb.ToString());
              //插入
            sb.Insert(0, "abc", 2);
            Console.WriteLine(sb.ToString());
            //移除
            sb.Remove(0, 2);
            Console.WriteLine(sb.ToString());
            //清空
            sb.Clear();
            Console.WriteLine(sb.ToString());

                                

一、概述
一、关于类与对象

1、为什么要学习面向对象编程?
答:面向过程编程,很难解决复杂业务逻辑和适应业务需求的变化。面向对象能够将程序很好的“模块化设计“,清晰的“分层组合”,方便的“业务扩展”。

2、从生活中的“类”转换到程序中的“类”
答:生活中很多东西都可以归为一个类。人:(男人、女人)
软件中的类,是为了处理相关的数据。

学校:学号、姓名、性别、班级、电话、地址.....
公司:编号、姓名、性别、部门、电话、地址、邮件....

...详细信息的时候,-->《对象》

//类包括:
静态属性:描述对象的基本特征信息(数据)(属性)
动态行为:描述这个对象能做什么,如何做?(方法)

汽车类:

类的基本概念:就是把一个事务中,我们所要关心特性和行为抽取出来,组合到一起,就称为一个类。

4、类的规范(组成)

访问修饰符  class  类的名称

    成员变量

     //字段部分

   成员函数
    
      //属性部分

      //方法部分
}

特别提示:一个类可以只有属性、只有方法、也可以属性、方法全部都有。
 

二、体验类与对象的使用

清楚:类只是规定了,它能存储什么类型的数据、能够完成什么任务,但是没有具体的数据。

类本身也是一种数据类型(自己定义的数据类型)

对象创建:以类为模板,给他赋值具体的数据。
特别的:使用new关键字,会将类调都内存中,从而以对象形式存在。

对象的属性:对象名.属性名=值;
对象的方法:对象名.方法名(参数...);

总结:
1、访问修饰符:默认是internal (内部的),只能在当前程序集内部使用这个类。
(类库、exe可启动项目)

public:公共的,可以在程序集外面使用。

2、类的名:使用pascal命名法(首字母大写)

三、对象的实例化
实例化一个对象语法是:
类名 对象名=new 类名()

三.类中包含 那些内容 大致分为        

字段和方法(成员变量和成员函数)

什么是字段

字段是类型的成员,称“成员变量”
与对象关联的字段亦称“实例字段”
与类关联的字段称为“静态字段”,由static修饰
字段的初始值
初始化时,字段获得其类型的默认值。
实例字段初始化的时机——对象创建时
静态字段初始化的时机——类型被加载时
只读字段
实例只读字段
静态只读字段
私有字段
不希望类中字段暴漏给其他类 可以使用private 描述字段  可以在构造函数重载中对其 赋值
或者使用属性赋值
 属性 和字段的关系
属性特点:

1.属性(Property) 是类(class)、结构(structure)和接口(interface)的命名成员

2.属性其实外界访问私有字段的入口   属性本质就是方法  一个属性可以分别有一个set 和get 方法组成。(或者称为访问器)

3.属性就是对字段的封装,set给某字段写入数据,get读取某字段的数据

属性的基本格式

public string Code
{
   get
   {
      return code;
   }
   set
   {
      code = value;
   }
}


三、属性(Property)
1、使用ILDasm反汇编工具发现get和set其实是两个方法,并且每一个属性都有对应的私有字段。
2、断点观察get和set发现,当我们给属性赋值的时候,其实是调用set方法,给对应的私有字段赋值,当读取属性值的时候,其实是调用了get方法,从对应的私有字段里面把值取出来。

属性:本身其实并没有保存数据,数据是保存到属性对应的私有字段中。。

属性是为了更好的实现需求的变化的扩展,从而让一个属性可以实现多样的需求!

3、属性的扩展
【1】增加业务判断逻辑。

 private int _test;
        public int Test
        {   
            set {
                if (value > 100)
                {
 
                    _test = 100;
                }
                else { 
                     _test = value;
                 }
            }
            get {
                return _test;
            } }


【2】设置只读字段功能

  private int _test =10;
       
        public int Test
        {   
            get {
                return _test;
            } }

【3】设置只读业务逻辑。(可以没有私有字段)

  public string Number  只读
        {
            get {
                string name = "zhangsan";
                return name;
            }  
           
        }


5、属性和字段对比

【1】字段,又称为“成员变量”
第一、目的:字段是为类的内部方法,或者方法之间传递数据使用,强调对内使用。
第二、修饰:字段一般用private修饰,很少用public。
第三、读写:字段可以读写均可,也可以用readonly限制为只读,但是不能添加业务逻辑。

【2】属性
第一、目的:属性是对外提供数据访问、本身不保存数据,强调对外使用。
第二、修饰:属性都是public,从来不用private。
第三、读写:属性可以轻松的实现单独读写控制,并且可以添加任意需要的业务逻辑。

   public int Test { get; set; } 可读可写


    
结论: 开发中,只要对外使用数据,都用属性,即使没有任何扩展业务,我也不建议使用public类型的字段(强烈建议)。过多使用public类型的字段,会显得你不专业。

6、属性使用的新特性扩展(4.6或以上版本)
【1】属性直接初始化 

public string StrNumber { get; set; } = "属性直接初始化";

【2】属性表达式

public string StrNumber2 { get => "属性表达式"; }
        public string StrNumber3 => "属性表达式";


7、对象类型的属性使用

总结:类本身就是一种数据类型(引用类型)所以,类中的属性或者变量(成员变量、局部变量)也可以是类类型(对象类型)

什么是方法
回顾以前内容
方法--构造函数
构造函数类型: 
构造函数分为实例构造函数、私有构造函数和静态构造函数 

实例构造函数:

实例构造函数又叫实例构造方法,它是一种特殊的成员函数,它主要用于为对象分配存储空间,对数据成员进行初始化.

实例构造函数的定义规则:

1、实例构造构造函数的名字必须与类同名

2、若在声明时未定义构造函数,系统会自动生成默认的构造函数

3、实例构造函数没有返回类型,它可以带参数,也可以不带参数

4.  构造方法的访问修饰符通常是public类型的,这样在其他类中都可以创建该类的对象

 5.构造方法是在创建类的对象时被调用的。通常会将一些对类中成员初始化的操作放到构造方法中去完成

 6、构造函数可以重载,从而提供初始化类对象的不同方法()

私有构造函数:

当没有实例字段或实例方法,当调用方法以获得类的实例时,私有构造函数可用于阻止创建类的实例。如果类中的所有方法都是静态的,可考虑使整个类成为静态的。

public class Counter
{
    private Counter() { }
    public static int currentCount;
    public static int IncrementCount()
    {
        return ++currentCount;
    }
}


静态构造函数 :

1、静态构造函数既没有访问修饰符,也没有参数。

2、创建第一个类实例或任何静态成员被引用时,自动调用静态构造函数来初始化类,也就是说我们无法直接调用静态构造函数,也就无法控制什么时候执行静态构造函数了。

3、一个类只能有一个静态构造函数。

4、无参数的构造函数可以与静态构造函数共存。尽管参数列表相同,但一个属于类,一个属于实例,所以不会冲突

5、如果没有写静态构造函数,而类中包含带有初始值设定的静态成员,那么编译器会自动生成默认的静态构造函数
 

public class TestClass
{
public static string strText;
static TestClass()
{
  strText = "aaaa"; 
}
} 


 析构函数:
垃圾回收程序最终销毁对象之前调用的方法,该方法称为析构函数

析构函数通常形式如下:

~类名()
{
 
 }


析构函数的声明类似构造函数,除了在析构函数开头要使用 ‘~’,另外要注意,析构函数,没有返回值,且不带任何参数。

析构函数的功能是用来释放一个对象的。在对象删除前,用它来做一些清理工作,它与构造函数的功能正好相反。

什么是垃圾回收
在编写程序时,会产生很多的数据 比如:int string 变量,这些数据都存储在内存里,如果不合理的管理他们,就会内存溢出导致程序崩溃

C#内置了自动垃圾回收GC,在编写代码时可以不需要担心内存溢出的问题 变量失去引用后 GC会帮我们自动回收.

什么样子的对象才会给回收?
GC只会回收 堆 的内存 ,而 值类型在 栈 中的使用完后马上就会给释放,并不需要 GC 进行处理,堆中的没有被引用或者null的对象才会被回收,静态的成员 会在程序结束后销毁。

什么时候进行垃圾回收?
什么时候回收这些都由操作系统决定,一般不需要进行理会全由系统调用,,明确如有特殊情况的需要进行释放 也可以强制的垃圾回收

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Test test = new Test();
            test = null;
            //强制开启回收
            GC.Collect();
            Console.ReadKey();
        }
    }
 
    public class Test {
        public int a;
        ~Test() {
            Console.WriteLine("ZHIXINGLE");
        }
 
   }

C#封装,继承,多态
面向对象特性: 封装、继承、多态 

三个特性主要目标:重用性(安全性)、灵活性和扩展性。

一,封装
 
将类的某些信息隐藏在类内部(private),不允许外部程序直接访问,而是通过该类提供的公共属性(public)来实现对隐藏信息的操作和访问

封装的好处
1、隐藏类的实现细节

2、只能通过规定属性访问数据

3、方便加入控制语句

4、方便修改实现

封装在c#中具体表现形式 :方法的封装    私有字段的封装(属性)  类的定义


二.继承
Why:解决功能重复问题

继承:一个类具有另一个类的属性和方法,这个类叫子类(派生类),另一个类叫父类(基类、超类)

继承的关键符号   :(冒号)

特征:

1、子类继承了父类的属性和方法(public、protected),但是构造方法不能被继

3、创建子类对象时,系统默认先调用父类构造方法,然后再调用子类构造方法

4、子类使用父类的属性和方法用  base 关键字(public、protected)

2、子类使用构造方法调用父类构造方法用 base()

5、转型:子类可以赋值给父类,但是父类不能赋值给子类

注意:

当父类有有参构造方法时,如果子类有构造方法(无参或有参),要求父类必须有一个无参构造方法。

如果子类没有构造方法,父类也需要提供一个无参构造方法。

如果不提供,子类构造方法会报错
 

this
this关键字  当前类的对象
注意:静态成员方法中不能使用this关键字,this关键字只能在实例构造函数、实例方法或实例访问器中使用
base
base关键字用于从派生类中访问基类的成员;
指定创建派生类实例时调用基类构造函数;
调用基类上已被重写的方法
注意:不能从静态方法中使用base关键字,base关键字只能在实例构造函数、实例方法或实例访问器中使用
  //多态

含义 :

即一个接口,多个功能  同一种操作作用于不同的对象,可以有不同的解释,产生不同的执行结果

包含:  重写    抽象类  接口   重载  

重载覆盖的发生条件:
重载,必然发生在一个类中,函数名相同,参数类型或者顺序不同构成重载,与返回类型无关
重写,必然发生在基类和派生类中,其类函数用virtual修饰,派生类用override修饰
覆盖,在子类中写一个和基类一样名字(参数不同也算)的非虚函数,会让基类中的函数被隐藏,编译后会提示要求使用New关键字

重写:

在子类和父类中,子类中的方法名称和父类方法名称相同,参数相同  

使用关键字 virtual,将父类的方法标记为虚方法,用 override  关键字,虚方法可以被子类重写

 public class Person
    {
        private string _name;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
 
        public Person(string  name)
        {
            this.Name = name;
        }
 
        public virtual void SayHello()
        {
            Console.WriteLine("我是人类");
        }
    }
 
    public class Chinese:Person
    {
        public Chinese(string name)
            :base(name)
        {
 
        }
 
        public override void SayHello()
        {
            Console.WriteLine("我是中国人,我叫{0}", this.Name);
        }
    }

重载(overload):在同一个类中,方法名称相同,参数不同(个数、类型),与返回值无关
 

抽象类    abstract

1.不能被实例化    不能创建对象

2.抽象类可以包括抽象方法,或者普通方法

3.抽象方法只能声明于抽象类中  其只能定义 不能实现。

4.继承抽象类的非抽象类,必须包含全部已继承的抽象方法和访问器的实现

5.通过包含使用  override 修饰符的属性声明,可在派生类中重写抽象类 方法和属性

6.抽象类也可以继承抽象类

用简单的话来说抽象类的功能就是:我是师傅(抽象类),你要是跟了(继承)师傅,你就必须得会干什么

例如:师傅会打人,那你也必须会打人,但你是轻轻的打,还是狠狠的打,你自己决定,但你必须得会打人。

类 DerivedClass 派生自抽象类 BaseClass。 抽象类包含抽象方法 AbstractMethod,以及两个抽象属性 X 和 Y
abstract class BaseClass  
{
    protected int _x = 100;
    protected int _y = 150;
    public abstract void AbstractMethod();   // Abstract method
    public abstract int X    { get; }
    public abstract int Y    { get; }
}
 
class DerivedClass : BaseClass
{
    public override void AbstractMethod()
    {
        _x++;
        _y++;
    }
 
    public override int X   // overriding property
    {
        get
        {
            return _x + 10;
        }
    }
 
    public override int Y   // overriding property
    {
        get
        {
            return _y + 10;
        }
    }
 
    static void Main()
    {
        var o = new DerivedClass();
        o.AbstractMethod();
        Console.WriteLine($"x = {o.X}, y = {o.Y}");
    }
}

接口

含义

接口定义了所有类继承接口时应遵循的语法合同 .用接口可以使程序更加清晰和条理化

1.接口使用 interface 关键字声明,它与类的声明类似。接口声明默认是 public 的

2.接口只包含了成员的声明( 方法 属性声明) 

3.接口中只能包含方法、属性、索引器和事件的声明。不允许声明成员上的修饰符,即使是pubilc都不行,因为接口成员总是公有的,也不能声明为虚拟和静态的。如果需要修饰符,最好让实现类来声明。

4.接口中定义的成员 需要继承类 来进行实现

5.接口也可以继承接口

6.一个类 可以继承多个接口  (接口就是c#实现多继承的方式)

接口和抽象类 区别和相同点

相同点: 不能实例对象    都可以被继承   都可以给继承类提供成员模板

不同点:接口只能有成员定义  抽象类 也可以包含成员的实现    接口可以实现多继承  抽象类只能单继承

密封类 

作用:

密封类可以用来限制继承性;

特点:

1.声明密封类时需要使用sealed关键字

2.密封类不能作为基类被继承,但它可以继承别的类或接口

3.密封类可以实例化对象

4.在密封类中不能声明受保护成员或虚成员

5. 将 abstract 修饰符用于密封类是错误的做法,

因为抽象类必须由提供抽象方法或属性的实现的类继承。

//生成 随机数

Random random = new Random();  得到的random就是一个随机数生成器,它可以用来生成随机数。

int Next(int minValue, int maxValue);
  这个方法能指定随机数的生成范围,左闭右开区间,即生成的数能包含minValue,不包含maxValue。可以包含负数。但是maxValue的值不能大于minValue的值,否则运行时会抛出异常。

int Next(int maxValue);
  这个方法指定随机数的最大值(不包含maxValue),并且它也只能生成非负整数,与Next(0, maxValue)是一个道理,如果传入的maxValue为负数,那么运行时抛出异常,如果maxValue的值为0或1,那么生成的随机数只能是0。

double NextDouble();
这个方法能返回一个大于或等于 0.0 且小于 1.0 的随机浮点数。
 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值