广元市建设局网站,工作英语,深圳工业设计公司推荐,昆明seo博客南网站建设介绍
这篇文章是我学习C#语言的笔记
学的是哔哩哔哩刘铁锰老师2014年的课程
在学习C#之前已经学习过C语言了。看的是哔哩哔哩比特鹏哥的课程。他们讲的都很不错
正在更新#xff0c;
大家可以在我的gitee仓库中下载笔记源文件、项目资料等
笔记源文件可以在Notion中导入…介绍
这篇文章是我学习C#语言的笔记
学的是哔哩哔哩刘铁锰老师2014年的课程
在学习C#之前已经学习过C语言了。看的是哔哩哔哩比特鹏哥的课程。他们讲的都很不错
正在更新
大家可以在我的gitee仓库中下载笔记源文件、项目资料等
笔记源文件可以在Notion中导入
介绍
这些是我在学习C语言的过程中自己练习的一些题目以及个人笔记
大家也可以参考着来学习
正在更新
大家可以在我的gitee仓库 中下载笔记源文件
笔记源文件可以在Notion中导入
一、类与名称空间
1. 简介
**类class**构成程序的主题**空间名称namespace**以树型结构组织类和其他类型 例如Button 和 Path 类。using 类似于 C语言的引用头文件在C#中是名称空间。
使用名称空间可以避免类的冲突。 比如Windows名称空间 与 IO 名称空间中都有Path 类。他们的作用不同但名称相同。这时候如果要使用就需要用 全限命名 xxx.xx.path
所以在以后使用时就要对类进行精确命名并且应该把他精确的放到 名称空间中去
2. 类库的引用
类库
是以.dll为结尾的文件。 dll为dynamic link Library 动态 链接 库。在项目树的references可查看在引用类库的时候要尤其注意依赖关系最好用依赖关系比较弱的包。在类库有问题时可以暂时用别的类库先替代。
类库的引用
类库可以有黑盒引用也可以有白盒引用 黑盒引用是对编译好的dll文件直接引用白盒引用是把源代码放到项目中直接引语
在生成项目的时候系统会自动引用一些必要的或者常用的库。可以再次选择系统自带的库也可以去引用别人或是自己曾经写的库
管理NuGet包
在使用类库时往往还需要更底层的类库。如果手动添加会比较麻烦。我们可以安装Entity Framework 安装后我们就不需要担心类库的依赖了。NuGet会自动管理依赖库。
白盒引用
朋友发给你他的项目你可以把他的项目添加到你的解决方案Solution中。
添加后就可以直接使用这个项目中的名称空间中的类
在解决方案中添加现有项目。然后在主项目中引用添加的项目
编译dll
我们要发给别人dll时需要创建醒目为Class Library。同样也可以在自己的项目中引用
3. 依赖关系
类或对象之间的耦合关系好的程序追求“高内聚低耦合” 高内聚指的是 类和名称空间精准的分类放置依赖关系也被称为耦合关系低耦合指的就是依赖关系低UML通用建模语言类图 类图用来展现类和类之间的关系。
二、类、对象、类成员、实例成员
类class
类class是现实世界对实物的模型 类是对现实世界事物进行抽象所得到的结果 事物包括“物质( 实体 )与“运动”( 逻辑)建模是一个去伪存真、由表及里的过程去伪存真的意思是在程序中去除用不到的功能表是我们最终达到的效果。里则是程序内封装的逻辑
类class与对象**instance**的关系
对象也叫实例instance是类经过“实例化”后得到的内存中的实体 Formallyinstanceis synonymous with“object”——对象和实例是一回事“飞机与”一架飞机有何区别天上有(一架)飞机——必需是实例飞概念是不能飞的有些类是不能实例化的比如“数学( Math class)我们不能说”一个数学依照类class我们可以创建对象这就是“实例化“ 现实世界中常称“对象”, 程序世界中常称“实例”二者并无太大区别常常混用初学者不必迷惑使用new操作符创建类的实例引用变量与实例的关系 孩子与气球气球不一定有孩子牵着多个孩子可以使用各自的绳子牵着同一个气球也可以都通过一根绳子牵着气球在现实世界中一般称作对象、在程序世界中一般称作实例以Form来举例 使用new来创建实例。使用Form MyForm1来创建引用变量可以理解为C语言指针使用MyForm1 new Form()来将引用变量绑定到实例上可以理解为指针指向实例不同于C需要解引用。 我们后续对MyForm1的操作实际上是对new Form() 这个创建的实例在操作
类的三大成员
属性Property 存储数据”组合起来表示类或对象当前的状态方法Method 由C语言中的函数(function)进化而来表示类或对象”能做什么’工作中90%的时间是在与方法打交道因为它是“真正做事”、”构成逻辑”的成员事件Event ) 类或对象通知其它类或对象的机制为C#所特有Java通过其它办法实现这个机制善用事件机制非常重要使用MSDN文档某些特殊类或对象在成员方面侧重点不同模型类或对象重在属性如Entity Framework工具类或对象重在方法如Math,Console通知类或对象重在事件如各种Timer
静态成员与实例成员*
一、语义及特点
静态成员
静态成员在语义上表示它是 “类的成员”可想象成班级里的公共用品如时钟也像人类的总数、平均身高体重等概念。它是与生俱来的只要类被抽象出来静态成员就存在。静态成员隶属于类本身在内存中只有一个副本。例如 Console.WriteLine 中的 WriteLine 是静态方法通过类名 Console 直接访问无需特定对象。静态成员可以被所有的对象访问而不需要通过特定的对象去访问。 同时静态成员只能访问其他静态成员不能访问类的实例成员。
实例成员
实例成员在语义上表示它是 “对象的成员”如同学生自己的书包每个学生对象都有自己独立的书包不同学生书包里的东西可能不一样。实例成员属于特定对象的实例每个对象都有自己的实例成员副本。实例成员需要通过实例化对象来访问 并且实例成员可以访问类的其他实例和静态成员。
二、访问方式
静态成员访问
静态成员可以通过类名直接访问如 Console.WriteLine 。
实例成员访问
实例成员需要通过实例化对象来访问如From from new From();。 这里的意思就是用From这个类。实例化了一个From对象。
当使用类名From来引出方法和工具时通常是调用静态方法或访问静态成员。
静态方法和成员属于类本身在内存中只有一份不依赖于特定的对象实例。可以直接通过类名来访问无需创建对象实例。例如From.StaticMethod();。静态成员不能直接访问类的实例成员因为它们与特定的对象实例无关。
使用实例名来引出方法和工具时是调用实例方法或访问实例成员。
实例方法和成员属于特定的对象实例每个对象实例都有自己独立的副本。必须先创建类的实例然后通过实例名来访问。例如from.InstanceMethod();。实例成员可以访问类的其他实例成员和静态成员因为它们在对象的上下文中运行。
总的来说主要区别在于静态成员和实例成员的本质特性以及访问方式不同。静态成员适用于与类相关的通用操作不依赖于特定的对象状态而实例成员则与特定的对象实例相关联反映对象的具体状态和行为。
三、基本元素、初识类型、变量与方法、算法简介
1. 章节介绍
构成C#语言的基本元素 标记( Token ) 标记 是对于编译器有意义的记号 关键字(Keyword)操作符(Operator)标识符(ldentifier)标点符号文本注释与空白简要介绍类型、变量与方法算法简介
2. 构成C#语言的基本结构
一、标记token概述
在 C# 中标记是对编译器有意义的记号主要分为以下几类 关键字具有特定含义的保留词汇如for循环中的 “for” 就是关键字。它们在语言中被赋予了特定的功能和用途用于构建程序的逻辑结构和表达特定的操作。 操作符用于执行各种运算如算术运算、-、*、/ 等、比较运算、!、、 等、逻辑运算、||、! 等。 标识符 “什么是合法的标识符” 部分主要涉及到在 C# 中定义变量、方法、类等命名时需要遵循的规则。合法的标识符通常由字母、数字和下划线组成但不能以数字开头。并且要不与C#的保留字 “大小写规范” 则涉及到 C# 中标识符的大小写敏感性。一般来说C# 是区分大小写的语言。 “命名规范” 包括各种命名约定如变量名通常使用小写字母开头的驼峰命名法myVariable类名使用大写字母开头的帕斯卡命名法MyVarable等。 一般变量名都是驼峰法。类、名称空间、等都是实用的帕斯卡法 标点符号在 C# 中标点符号用于分隔语句、表示语句的结束等例如分号;用于结束一条语句括号()用于方法调用和表达式分组等。 文本字面值 “整数” 可以有多种后缀例如 “L” 表示 long 类型的整数“U” 表示 unsigned 整数等2、2L。“实数” 也有多种后缀用于表示不同精度的浮点数。F单精度D双精度默认双精度。“字符字符串” 用于表示一串字符用双引号括起来。“布尔” 类型只有两个值true 和 false。“空null” 表示一个对象没有值。
二、注释与空白
单行注释使用 “//” 开头用于在代码中添加单行注释解释代码的功能或提供其他信息。多行块注释使用 “/” 和 “/” 包围起来可以包含多行注释内容。多行注释通常用于对一段代码或一个函数进行详细的解释。
3. 初识类型、变量和方法
初识类型 (Type) 亦称数据类型 (Data Type)。不同的数据类型在内存中占据不同的空间大小并且具有特定的操作和用途。例如整数类型用于存储整数值浮点类型用于存储带有小数部分的数值。变量是存放数据的地方简称 “数据” 变量的声明在 C# 中变量的声明需要指定变量的类型和名称。例如int num;声明了一个名为num的整数类型变量。变量的使用声明变量后可以通过赋值语句为变量赋予具体的值。例如num 10;将整数值 10 赋给变量num。变量可以在表达式中使用也可以作为方法的参数传递。方法 (旧称函数) 是处理数据的逻辑又称 “算法” 方法的声明方法的声明包括方法的返回类型、方法名、参数列表和方法体。例如public int Add(int a, int b) { int result a b; return result; }声明了一个名为Add的方法该方法接受两个整数参数a和b并返回它们的和。其中public 是 为了让 类 外边 也能访问到这个方法。方法的调用可以通过方法名和参数列表来调用方法。但在此之前 要把类创建为实例。然后再使用int sum c.Add(5, 3);调用了Add方法并将返回值赋给变量sum。其中c为创建的实例名方法一般分为三类有输入有输出例如求和没输入有输出例如显示日期无输入有输出。一般是在方法内直接输出或者做了某些事情。程序 数据 算法 有了变量和方法就可以写有意义的程序了。程序通过对数据的操作和处理来实现特定的功能。变量存储程序中的数据方法提供对数据的处理逻辑。通过合理地组织变量和方法可以构建出复杂的程序。一般有for 和 递归。
在 C# 中正确地理解和使用数据类型、变量和方法是编写高效、可靠程序的基础。了解不同数据类型的特点和用途合理地声明和使用变量以及设计有效的方法可以提高程序的可读性、可维护性和性能。
四、详解C#类型、变量与对象
什么是类型(Type)
一、又名数据类型( Data Type )
A data type is a homogeneous collection of values, effectively presented, equipped with a set of operations which manipulate these values数据类型是值的同质集合有效地呈现配备了一组操作这些值的操作是数据在内存中存储时的“型号Type 又称型号若误小内存容纳大尺寸数据会丢失精确度、发生大内存容纳小尺寸数据会导致浪费编程语言的数据类型与数据的数据类型不完全相同
二、强类型语言与弱类型语言的比较
数据被数据类型约束叫强类型语言。反之被约束的少甚至不约束。叫弱类型 C语言示例:if条件 例如在C语言中 if(x 10)是可以被编译过去的。 而 C#语言则不允许 因为C#语言中 括号内强制 要求为一个bool类型的值也就是只能为true 和 false JavaScript示例:动态类型 var myVar 100; myVar “hello”; alert(myVar); 这段代码在这里是可以运行的 C#语言对弱类型/动态类型的模仿 在C#语言中为了模仿弱类型引用了一个新的关键字dynamic 这个关键字可以实现上边的功能
在C#语言中的作用
一、程序的静态与动态时期
程序在执行时为动态时期运行时期也称为运行或调试阶段。在这个阶段程序被加载到内存中运行。可以说动态的程序是在内存里的此时方法调用使用栈Stack存储对象使用堆Heap。
而在静态时期即写代码或编译阶段程序以代码文件的形式存储在硬盘里。
二、栈Stack的特点
栈的空间相对较小一般为 1 - 2M但其速度快。当方法被调用时方法的参数和局部变量会在栈上分配内存。由于栈的内存空间有限当不断进行方法调用或在方法中不断创建新的变量导致栈满时就会出现栈溢出Stack overflow的情况。例如可以通过直接递归某个方法在方法中不断创建新的变量来测试栈溢出或者在方法前添加unsafe前缀后使用int* p stackalloc int(9999999);在栈中切除很大的一块内存也可能引发栈溢出。
三、堆Heap的特点
堆的空间相对较大能有几个 G。对象存储在堆上在堆上分配内存相对较慢。同时堆可能会出现内存泄漏的情况即如果程序员忘记释放不再使用的内存就会导致内存浪费。不过C# 有垃圾收集器的机制垃圾收集器会自动收集不再使用的对象所占用的内存空间从而在一定程度上避免了内存泄漏的问题。
在C#语言中的作用
一个C#类型中所包含的信息有 存储此类型变量所需的内存空间大小此类型的值可表示的最大、最小值范围此类型所包含的成员(如方法、属性、事件等 )此类型由何基类派生而来程序运行的时候此类型的变量在分配在内存的什么位置 Stack简介Stack overflowHeap简介使用Performance Monitor查看进程的堆内存使用量关于内存泄漏此类型所允许的操作(运算)
C#语言的类型系统
一、C#的五大数据类型
类(Classes): 如Windows, Form, Console, String结构体(Structures): 如Int32, Int64, Single, Double枚举(Enumerations): 如HorizontalAlignment, Visibility接口(Interfaces )委托(Delegates )
二、C#类型的派生谱系 C shap中 的类型分为两种引用类型和值类型。引用类型分为类、接口、委托值类型有结构体和枚举。所有类型都以Object类型为自己的基类型。
第一组左边
Object、string 为真正的数据类型因为这两个太常用了。所以C#把他吸收为自己的关键字了。 string 为 引用类型 存储在 堆横线下边的三个数据类型 不是具体的数据类型而是我们用他们三个关键字去定义自己的数据类型
第二组
同上
第三组
上为bool类型的值中为 无返回值 和 为空下为 声明变量
变量、对象与内存
什么是变量 表面上来看变量的用途是存储数据 实际上变量表示了存储位置并且每个变量都有一个类型以决定什么样的值能够存入变量 变量名对应这变量的值在内存中存储位置 并且决定了什么样的值能够存融入 变量一共有7种· 静态变量静态字段实例变量(成员变量,字段), 数组元素, 值参数, 引用参数, 输出参数, 局部变量 ref 引用的 值参数 为引用变量。out 引用的 值参数 为输出参数 一般称的变量为局部变量 狭义的变量指局部变量因为其它种类的变量都有自己的约定名称 简单地讲局部变量就是方法体(函数体)里声明的变量 变量的声明 有效的修饰符组合opt - 类型 - 变量名 - 初始化器opt。 opt意思就是可有可无 比如public static int Age 0:; public static 是有效的修饰符组合 int 为类型 Age 为变量名 0 则为初始化器 总结 ”变量 以变量名所对应的内存地址为起点、以其数据类型所要求的存储空间为长度的一块内存区域“ 大小端 与硬件有关 值类型在栈上分配内存不同的值类型占用的字节大小固定如byte占用 1 个字节int占用 4 个字节等。 引用类型的对象在堆上分配内存引用本身在 32 位系统上通常占用 4 个字节在 64 位系统上通常占用 8 个字节它只是指向堆上对象的内存地址。 栈内存的增长方向通常是由高地址向低地址 值类型的变量 以byte / sbtye / short / ushort为例值类型没有实例所谓的“实例”与变量合而为一 也就是说int x; 相当于 int x new int x();引用类型的变量与实例 引用类型变量与实例的关系:引用类型变量里存储的数据是对象的内存地址变量的默认值常量(值不可改变的变量) const装箱与拆箱(Boxing Unboxing) 当把一个值类型转换为object类型时会发生装箱操作。 object obj obj 变量是在栈上的 例如将一个整数赋值给object变量 int num 10;
object obj num;在这个过程中会在堆上创建一个新的对象并将值类型的值复制到这个对象中。同时在栈上会存储对这个堆上对象的引用。 当从object类型转换回值类型时会发生拆箱操作。例如 object obj 20;
int num (int)obj;在拆箱过程中首先要检查堆上的对象是否为正确的类型如果是则将值从堆上的对象复制到栈上的值类型变量中。 总的来说装箱和拆箱操作涉及到堆和栈的交互。 装箱时值类型的值被复制到堆上的对象中栈上存储对堆上对象的引用 拆箱时从堆上的对象中复制值到栈上的值类型变量中。 这些操作会带来一些性能开销
五、方法的定义、调用和调试
方法在创建时被static 修饰 会变为 类的方法。 否则为 实例的方法。
实例的方法只有在创建出实例后用实例引出。
静态的方法会一直占用内存 实例 则可以被释放
调用方法的()为 方法调用操作符
构造器(一种特殊的方法)
构造器(constructor)是类型的成员之一
狭义的构造器指的是“实例构造器(instance constructor )
声明和调用构造器
在 C# 中当我们写好一个类之后如果没有进行额外的操作系统会自动提供一个默认的构造器。这个默认构造器会将类中没有赋值的参数初始化为默认值。例如
class Student
{public int ID;public string Name;
}此时若调用 Console.WriteLine(student.ID); 和 Console.WriteLine(student.Name);那么输出就是 0 和空字符串。 我们也可以自己创建构造器。由于构造器没有输入与输出所以可以像下面这样创建
class Student
{public Student(){this.ID 1;this.Name No Name;}public int ID;public string Name;
}这样当创建一个 Student 类的实例时使用默认构造器初始化后的输出就是 1 和 No Name。 当然我们还可以在创建实例时要求给变量初始值这就是构造函数重载。例如
class Student
{public Student(){this.ID 1;this.Name No Name;}public Student(int intId, string intName){this.ID intId;this.Name intName;}public int ID;public string Name;
}现在当我们运行以下代码
static void Main(string[] args)
{// 创建实例为默认Student student new Student();Console.WriteLine(student.ID);Console.WriteLine(student.Name);Console.WriteLine();// 键入值创建实例Student student2 new Student(2, Hello);Console.WriteLine(student2.ID);Console.WriteLine(student2.Name);
}输出结果为先是 1 和 No Name接着是一个分隔符 然后是 2 和 Hello。通过构造函数重载我们可以根据不同的需求灵活地初始化类的实例。
构造器的内存原理
在 C# 中对于类Student含有int ID和string Name两个成员变量。
当类中没有显式编写构造器时即使用默认构造器。 此时创建实例Student stu new Student();在内存中的操作如下首先在栈区为变量stu分配内存该内存用于保存堆区中实例的地址。接着在堆区为int类型的ID和string类型的Name各分配四个字节的内存。其中int类型的四个字节会以小端的补码形式存入而string类型在默认情况下会被初始化为指向空字符。
当类中自己创建了构造器并且在构造器中将ID赋值为 1Name赋值为 Hello。当创建实例Student stu new Student();时内存操作过程与默认构造器类似首先在栈区为stu变量分配内存以保存堆区实例地址。然后在堆区为int和string各分配四个字节内存。对于int类型依旧以小端的方式存入数字 1。对于string类型系统会在堆区另外开辟足够大的内存空间来存储 Hello 字符串然后Name会指向堆区这个存储 Hello 的地址以小端的补码形式存储在内存中。
总之构造器的不同 会影响堆区中对象的初始化方式进而影响内存的分配和数据的存储。
方法的重载(Overload )
声明带有重载的方法
方法签名由方法的名称、类型形参的个数以及它的每一个形参按从左到右的顺序的类型和种类值、引用或输出组成。需注意方法签名不包含返回类型。
同样实例构造器签名由它的每一个形参按从左到右的顺序的类型和种类组成。
重载决策是在给定了参数列表和一组候选函数成员的情况下选择一个最佳函数成员来实施调用。例如在 C# 中常见的 Console.WriteLine 方法就有多种重载形式可以根据不同的参数类型输出不同的内容。
下面以一个简单的计算器类为例
class Calculator
{public int Add(int a, int b){return a b;}// 形参个数不同public int Add(int a, int b, int c){return a b c;}// 形参类型不同public double Add(double a, double b){return a b;}// 形参种类不同public int Add(ref int a, int b){a 100;return a b;}
}在这个例子中Calculator类中的Add方法有多个重载版本。当调用这个方法时编译器会根据传入的参数来确定具体调用哪个重载的方法。 对于方法的重载作为初学者要记住方法的名字可以相同但它的参数列表不能完全一样即参数的个数、类型或种类不同从而形成不同的方法签名。这样在调用方法时编译器可以根据传入的参数来确定具体调用哪个重载的方法。 如何对方法进行debug
Call Stack 调用堆栈 可以看注意看栈的深度函数之间的调用调用调用
还有看变量这个很熟悉了不写了
方法的调用与栈*
栈内存的增长方向是由高字节位向低字节位发展当不断进行方法调用而栈内存使用达到其最大限度时层级过深就会出现 “Stack overflow栈溢出” 的情况。
对栈帧stack frame进行分析可以更好地理解方法调用在栈中的布局。首先程序从main方法开始执行main方法会占用一部分栈空间。当main方法调用其他方法时main方法成为主调者caller被调用的方法成为被调者callee。
在调用方法时传入的参数如果是变量这些变量会被压入栈中。在 C# 语言中这些变量由主调者这里即main方法管理并且是从左往右依次压入栈的。所以传入的变量都处于主调者的栈帧中。
接着进入被调用的方法被调用者的局部变量由被调用方法管理。如果在这个方法中又调用了其他方法同样遵循上述规则。
当方法执行完毕准备退出时会首先将返回值存入 CPU 寄存器如果寄存器空间不够可能会采用在栈中开辟空间。CPU寄存器根据型号不同个数不同。一般就几个。然后销毁被调用方法中的局部变量。接着销毁上一个调用者主调者传过来的参数。最后将返回值赋值给上一个调用者的某个局部变量以便主调者继续执行后续代码。
总的来说栈按照压入的顺序进行操作后进先出。每个方法的调用都会在栈上创建一个新的栈帧包含方法的参数和局部变量等信息。当方法执行完毕对应的栈帧被销毁释放内存空间。这种栈的管理方式确保了方法调用的正确执行和内存的有效管理。
#、上课的小知识点 var 匿名变量可根据不同的变量类型自动改变自己。 注意只能在创建的同时赋值var a “abc”var 123var 123.00 不能先创建后续赋值 var a; a “abc“。 {0} 为占位符,后续则为 {1}.{2}.. {0:F} 也可以这么用意思是输出F类型的
#、小知识点
$符号用于字符串插值。| 字符串插值允许你在字符串字面量中包含表达式以更简洁和易读的方式构造字符串。object是所有类型的基类这意味着任何类型的对象都可以被视为object类型。例如可以将整数、字符串、自定义类的实例等赋值给object类型的变量。this.xxx意思是当前 类 中 的某个 方法想要使用指针需要在方法中添加 unsafe 不安全的前缀ctor Tab Tab 会自动写构造器