【学习笔记】c#基础学习

现在开启c#学习之旅,因为有java基础,感觉c#非常熟悉,而unity相关库就跟spring这种框架类似,所以准备先把c#基础过一遍,然后再看一下unity库 哪几种类(估计也是动画 声音 碰撞 特效这种),类的详细使用估计要在实战中,所以,这里只是一个入门我打算。

因为有java基础,所以我打算看其他类似跳槽up的文章总结,加快速度。
否则看菜鸟教程这种既浪费时间又容易脱离目标(快速进行实战开发)
在这里插入图片描述
好吧,其他up也是看菜鸟的,我还是耐心点…(而且底部会有其他人的备注补充 赞)

出现了个问题,代码无法运行,啊这…

基本类型

在这里插入图片描述

java和c#中拆箱装箱的区别

C#中为什么没有Java的包装类Integer?
C#的类型系统中万物皆对象,不存在Java这种模棱两可莫名其妙的“基本类型”,int既为Int32类型,是一个struct值类型,只要List的泛型约束没有特殊的限制,这里只要写某种对象对应的类型就可以了,不存在不是对象不能写的类型。

值类型变量可以直接分配给一个值。它们是从类 System.ValueType 中派生的。
(这里提到了struct值类型,后续再研究)

C#与java的比较之装箱和拆箱,数据类型
c#装箱拆箱是转换成object,java是转换成对应的包装类如Integer Long等

object Object区别,string String区别?

小object是大Object的一个别名(C#),就如小int是Int32的别名一样。
他们编译后(通过一个叫通用类型系统的啥)小object会变成大Object,
小int会变成Int32.所以你爱大的就用大的 爱用小的就用小的

在这里插入图片描述

常量 const

在这里插入图片描述

方法参数 ref out in

好像是c#的引用传递,和java的值传递还不同,java没有这种概念,插个眼,后续深入
参考:C# in out ref关键字

动态(Dynamic)类型

一开始我以为是跟java中var类似,结果c#也有var,var是静态隐式申明类型,简单来说动态类型就是运行时确定的类型
【这篇讲得细且明白】C#基础知识系列专题十七:深入理解动态类型
在这里插入图片描述
能做到动态改变变量类型的事(?),以及调用python等动态语言,还听到别人提到json解析的便利性等等
在这里插入图片描述
原理嘛看不懂,先贴这了
在这里插入图片描述

在C#中用Var 和 Dynamic声明变量的区别
C# 中的动态类型

逐字字符串 @

在这里插入图片描述

类型转换

类型转换中,我看有人把这个叫作隐式类型转换
在这里插入图片描述

java中这种叫多态,即父类引用指向子类对象


java也有类似parse,像Long.parseInt这种
在这里插入图片描述在这里插入图片描述

运算符-其他运算符

在这里插入图片描述
is感觉就是 java 的instanceof,而as java没有,只有用“()”强制类型转换了

Console.WriteLine("int 的大小是 {0}", sizeof(int));//int 的大小是 4
Type type = typeof(string);//typeof 关键字用于获取一个类型的类型对象,它通常用于反射和动态创建类型实例。
Console.WriteLine(type.FullName);//System.String

封装

封装 被定义为"把一个或多个项目封闭在一个物理的或者逻辑的包中"。在面向对象程序设计方法论中,封装是为了防止对实现细节的访问。

抽象和封装是面向对象程序设计的相关特性。抽象允许相关信息可视化,封装则使开发者实现所需级别的抽象。

C# 封装根据具体的需要,设置使用者的访问权限,并通过 访问修饰符 来实现。

一个 访问修饰符 定义了一个类成员的范围和可见性。C# 支持的访问修饰符如下所示:

  • public:所有对象都可以访问;
  • private:对象本身在对象内部可以访问;
  • protected:只有该类对象及其子类对象可以访问
  • internal:同一个程序集的对象可以访问;
  • protected internal:访问限于当前程序集或派生自包含类的类型。
    在这里插入图片描述

在这里插入图片描述

同一程序集的文件中可访问,程序集是经由编译器编译得到的,供CLR进一步编译执行的那个中间产物,在WINDOWS系统中,它一般表现为·dll或者是·exe的格式。

对于一个大型的项目,通常由多个DLL文件组成,引用这些DLL,就能访问DLL里面的类和类里面的方法。
比如,一个记录日志的DLL,任何项目只要引用此DLL就能实现记录日志的功能。这个DLL文件的程序就是一个程序集。
当另外一个项目引用此DLL时,不能引用internal修饰的类或者方法,这就叫做只能在程序集中访问

方法参数传递

方式 描述
值参数 这种方式复制参数的实际值给函数的形式参数,实参和形参使用的是两个不同内存中的值。在这种情况下,当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全。
引用参数 这种方式复制参数的内存位置的引用给形式参数。这意味着,当形参的值发生改变时,同时也改变实参的值。
输出参数 这种方式可以返回多个值。
ref 与 out区别

首先:两者都是按地址传递的,使用后都将改变原来参数的数值。

其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所以你必须初始化一次。这个就是两个的区别,或者说就像有的网友说的,ref是有进有出,out是只出不进。
在这里插入图片描述在这里插入图片描述
ref out参数不同的可以重载 但目前测试发现只跳转无out关键字的方法,不知道原理,之后有空再搜索研究。

可空类型(Nullable)

? 单问号用于对 int、double、bool 等无法直接赋值为 null 的数据类型进行 null 的赋值,意思是这个数据类型是 Nullable 类型的。

int? i = 3;
等同于:

Nullable<int> i = new Nullable<int>(3);
int i; //默认值0
int? ii; //默认值null

?? 可以理解为三元运算符的简化形式:

num3 = num1 ?? 5.34;//等价于↓↓
num3 = (num1 == null) ? 5.34 : num1;

数组

c#中有多维数组和交错数组,跟java不太一样,交错数组元素长度可以不一样
在这里插入图片描述

params关键字

params关键字修饰数组,就是变成可变长参数,类似java的“…”号:String...args
在这里插入图片描述
params注意事项:

  1. 带 params 关键字的参数类型必须是一维数组,不能使用在多维数组上;
  2. 不允许和 ref、out 同时使用;
  3. 带 params 关键字的参数必须是最后一个参数,并且在方法声明中只允许一个 params 关键字。
  4. 不能仅使用 params 来使用重载方法。
  5. 没有 params 关键字的方法的优先级高于带有params关键字的方法的优先级

然后发现了个不错的博客,也是学过java的人学习c#时的笔记,总结得挺好,可以参考下
C#和Java在语法上的一些区别

结构体Struct

C# 中结构体和类在语法上非常相似,他们都是一种数据结构,都可以包括数据成员和方法成员。

结构体特点

在这里插入图片描述

结构体与类区别
  1. 结构是值类型,它在栈中分配空间;而类是引用类型,它在堆中分配空间,栈中保存的只是引用。
  2. 结构类型直接存储成员数据,让其他类的数据位于堆中,位于栈中的变量保存的是指向堆中数据对象的引用。
  3. 结构体中声明的字段无法赋予初值,类可以
  4. 结构体的构造函数中,必须为结构体所有字段赋值,类的构造函数无此限制
类与结构体选择

首先明确,类的对象是存储在堆空间中,结构存储在栈中。堆空间大,但访问速度较慢,栈空间小,访问速度相对更快。故而,当我们描述一个轻量级对象的时候,结构可提高效率,成本更低。当然,这也得从需求出发,假如我们在传值的时候希望传递的是对象的引用地址而不是对象的拷贝,就应该使用类了。

  1. 当堆栈的空间很有限,且有大量的逻辑对象时,创建类要比创建结构好一些;
  2. 对于点、矩形和颜色这样的轻量对象,假如要声明一个含有许多个颜色对象的数组,则CLR需要为每个对象分配内存,在这种情况下,使用结构的成本较低;
  3. 在表现抽象和多级别的对象层次时,类是最好的选择,因为结构不支持继承。
  4. 大多数情况下,目标类型只是含有一些数据,或者以数据为主。

结构体java没有这个概念,现在只是浅浅留个印象,以后再深入了解一下。

枚举enum

C# 枚举是值类型。适用于某些取值范围有限的数据,例如:我只想要春夏秋冬这四个字符的取值范围,如果用string的话就无法固定取值范围

  • 枚举语法:[访问权限修饰符] enum 枚举名 { 枚举值 }
enum Days {
    
     Sun, Mon, tue, Wed, thu, Fri, Sat };
  • 枚举访问权限修饰符和类是一样的,默认访问权限和类一样都是internal
  • 枚举名遵循大驼峰命名法,建议枚举类名建议带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。
说明: 枚举其实就是特殊的常量类,且构造方法被默认强制是私有。
正例: 枚举名字: DealStatusEnum, 成员名称: SUCCESS / UNKOWN_REASON
  • 枚举的每一个值都是一个整型,默认都是从 0 开始,后续等差为1。
    • 枚举中的元素的值可以设置为相同,但不推荐。
    • 枚举位标志在这里插入图片描述
    • 枚举元素默认的值的类型是 int 型,可以修改为其他整型 byte、sbyte、short、ushort、int、uint、long 和 ulong。
    • 不全部赋值的话,第 n 个符号值= 第n-1符号值 + 1
enum Day  {
    
    a=8,b,c=1,e,f,g};//则序号依次为8,9,1,2,3,4

类class

  • 我们可以使用 static 关键字把类成员定义为静态的。当我们声明一个类成员为静态时,意味着无论有多少个类的对象被创建,只会有一个该静态成员的副本。
析构函数

析构函数用于析构类的实例。

  • 用法是在类的名称前加上一个波浪形(~)作为前缀,没有修饰符,也没有参数。
class Line
   {
    
    
      public Line()  // 构造函数
      {
    
    
         Console.WriteLine("对象已创建");
      }
      ~Line() //析构函数
      {
    
    
         Console.WriteLine("对象已删除");
      }
   }
  • 不能在结构中定义析构函数。只能对类使用析构函数。
  • 一个类只能有一个析构函数。
  • 无法继承或重载析构函数。
  • 无法调用析构函数。它们是被自动调用的。

析构函数与Object.Finalize有关,后续遇到再深入学习吧,涉及垃圾回收机制。

继承

继承用“:”,相当于java中的extends。

class <派生类> : <基类>
{
    
    
 ...
}

和java相同,c#不支持多重继承,但能多实现。

至于抽象类中的虚方法virtual,感觉和java 中抽象类的default方法差不多,提供了默认实现而已。

多态
  • 多态:同一个行为具有多个不同表现形式或形态的能力
  • 静态多态:方法重载、运算符重载
  • 动态多态:三个必要条件,继承、重写、父类引用指向子类对象
抽象

虚方法

  • 当有一个定义在类中的函数需要在继承类中实现时,可以使用虚方法,虚方法是使用关键字​​virtual​​声明的,虚方法可以在不同的继承类中有不同的实现,即为基类中定义的允许在派生类中重写的方法;
  • 子类继承虚拟类可以实现虚拟方法也可以不实现虚拟方法;
  • c#的base相当于java 的super,用于调用父类的方法;
  • 一定要注意,只有为虚方法时可以进行重写,不能对非虚方法进行重写;
    在这里插入图片描述
  • 虚方法一般在基类定义,在派生类中实现具体操作,派生类实现该方法时,要用​​override​​对其方法进行修饰;
  • 当用​​virtual​​修饰后,不允许再有 ​​static​​、​​abstract​​ 或者 ​​override​​ 修饰符;

参考:C#中虚方法(virtual)详解

new override

接口

接口的定义是指定一组函数成员而不实现成员的引用类型,其它类型和接口可以继承接口。定义还是很好理解的,但是没有反映特点,接口主要有以下特点:

  • 通过接口可以实现多重继承,C# 接口的成员不能有 public、protected、internal、private 等修饰符。原因很简单,接口里面的方法都需要由外面接口实现去实现方法体,那么其修饰符必然是 public。C# 接口中的成员默认是 public 的,java 中是可以加 public 的。
  • 接口成员不能有 new、static、abstract、override、virtual 修饰符。有一点要注意,当一个接口实现一个接口,这2个接口中有相同的方法时,可用 new 关键字隐藏父接口中的方法。
  • 接口中只包含成员的签名,接口没有构造函数,所以不能直接使用 new 对接口进行实例化。接口中只能包含方法、属性、事件和索引的组合。接口一旦被实现,实现类必须实现接口中的所有成员,除非实现类本身是抽象类。
  • C# 是单继承,接口是解决 C# 里面类可以同时继承多个基类的问题。
接口与抽象类的区别
  • 接口用于规范,抽象类用于共性。抽象类是类,所以只能被单继承,但是接口却可以一次实现多个。
  • 接口中只能声明方法,属性,事件,索引器。而抽象类中可以有方法的实现,也可以定义非静态的类变量。
  • 抽象类可以提供某些方法的部分实现,接口不可以。抽象类的实例是它的子类给出的。接口的实例是实现接口的类给出的。
  • 在抽象类中加入一个方法,那么它的子类就同时有了这个方法。而在接口中加入新的方法,那么实现它的类就要重新编写(这就是为什么说接口是一个类的规范了)。
  • 接口成员被定义为公共的,但抽象类的成员也可以是私有的、受保护的、内部的或受保护的内部成员(其中受保护的内部成员只能在应用程序的代码或派生类中访问)。
  • 此外接口不能包含字段、构造函数、析构函数、静态成员或常量。
  • 还有一点,我们在VS中实现接口时会发现有2个选项,一个是实现接口,一个是显示实现接口。实现接口就是我们平常理解的实现接口,而显示实现接口的话,实现的方法是属于接口的,而不是属于实现类的。

命名空间 namespace 与using

相当于java中的package,用于类隔离。(啊这,差别还挺大!!!)

  • 我就纳闷了,一个cs文件能包含多个namespace,那到底执行的是哪个namespace下的程序呢?
  • 以及cs文件没有namespace也能正常运行,难道有默认命名空间吗,那其他类怎么去调用这个无namespace的类呢?

C#代码里没有命名空间“namespace —{}”但也可以运行,为什么?
C#并没有用Namespace包裹内容,请问默认会在什么namespace下呢?
看了上面两个参考大概有些解答,以后反编译再看看吧,以及没namespace的怎么被调用,不浪费时间看了。

C# 预处理器指令

在程序调试和运行上有重要的作用。比如预处理器指令可以禁止编译器编译代码的某一部分,如果计划发布两个版本的代码,即基本版本和有更多功能的企业版本,就可以使用这些预处理器指令来控制。在编译软件的基本版本时,使用预处理器指令还可以禁止编译器编译于额外功能相关的代码。另外,在编写提供调试信息的代码时,也可以使用预处理器指令进行控制。总的来说和普通的控制语句(if等)功能类似,方便在于预处理器指令包含的未执行部分是不需要编译的。

好像目前用不到,也好像没啥作用,跳过。

可以参考菜鸟底部备注

目前为止,把c#基础部分搞完了,花了四五天,除了第一天和今天,其他时间效率不高,自我批评下。
后续进阶部分(属性事件反射等)先简单过一遍,知道大概名词,后续遇到再继续深入了解。

猜你喜欢

转载自blog.csdn.net/weixin_44013533/article/details/129850075