C#语言及其特点
- C#是一门面向对象的、运行于
.NET Framework
和.NET Core
的程序设计语言,由C
和C++
衍生出来 - C#安全、稳定、简单、优雅、跨平台
.NET 5
之后.NET Framework
和.NET Core
统称为.NET
.NET和C#之间的关系
.NET
平台上可以运行多门语言,其中C#
是最适合在.NET
平台上运行的语言
C#语法结构
cs文件结构
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyFirstWinFormApp
{
public class Class1
{
public static void Main()
{
}
}
}
- 引用命名空间:
using System;
- 项目的命名空间,大多数时候也是项目本身的名称:
namespace MyFirstWinFormApp
可以简单的理解为文件夹 - 类名称:
public class Class1
- 方法或者叫函数:
public static void Main()
- 大括号内即为方法方法体,用于写具体方法代码
- Main方法: 是所有C#程序的入口点,Main方法说明当执行时,类将做什么动作,Main方法通过方法体中的语句指定它的行为
- NET6之后,namespace的大括号可以省略,namespace后加个分号
C#基本语法
C#是面向对象的,在面向对象的程序设计方法中,程序由各种对象组成,相同种类的对象往往有相同的类型
注
- C#是大小写敏感的
- 所有的语句和表达式必须以分号结尾
- 与Java不用的是,文件名可以与类名不相同
- 一个C#文件中可以有多个类
关键字
关键字是对程序编译器有特殊意义的预定义保留标识符,它们不能在程序中用作标识符
例:
using
: 程序中包含命名空间,一个程序中可以包含多个using
语句class
: 用于声明一个类
注释
- C#的注释方式
/*
C#多行注释
*/
- 行注释
// C#单行注释
- 文档注释
/// C#文档注释
变量
变量是一个供程序存储数据盒子
在C#中,每个变量都有一个特定的类型,不同类型的变量其内存也不尽相同
- 整数类型:
byte(8位)、short(16位)、int(32位)、long
- 浮点型:
float、double
- 十进制类型:
decimal
- 布尔类型:
bool
- 字符类型:
string、char
- 空类型:
null
decimal
-
一般使用
decimal
进行金钱计算,但是依然会有精度损失 -
不是基础类型,不要直接使用
decimal
这个类型来进行计算,会产生很大的系统开销 -
decimal
和其他基本类型之间不通用 -
定义
decimal
例:decimal dc = 1.1m
注
- 数据类型之间的转换只能低精度转换为高精度
- 定义float时,数字后需要加f,例:
float f = 1.1f;
- 值类型: 在我们没有给变量赋初值的时候,系统会默认给赋初值;可以在变量类型后加问好,系统就不会自动赋初值:
int? a;
字符类型(string/char)
定义方式:
string str = "...";
char ch = '.';
基础知识
Solution和Project
Solution
: 针对客户需求的总的解决方案Project
: 解决具体的某个问题,一个Solution
可以有多个Project
类与名称空间
类(class)是最基础的
C#
类型类是一个数据结构,将状态(字段)和操作(方法和其他函数成员)组合在一个单元中
类为动态创建的类实例(
instance
)提供了定义,实例也称为对象(object
),类支持继承(inheritance
)和多态性(polymorphism
),这是派生类(derived
)可用来扩展和专用化基类()的机制
类(class
): 构成程序的主体
名称空间(namespace
): 以树形结构组织类和其他类型
类库的引用
类库引用是使用名称空间的物理基础,不同技术类型的项目会默认引用不同的类库
DDL
引用(黑盒引用,无源代码)NuGet
- 项目引用(白盒引用,有源代码)
- 类库(
Class Library
)
- 类库(
类与对象
类是对现实世界事务进行抽象得到的结果
事物包括“物质”(实体)和“运动”(逻辑)
对象也就是实例,是类经过“实例化”后得到的内存中的实体
类的三大成员:
- 属性(Property): 存储数据,组合起来可以表示类或对象当前的状态
- 方法(Method): 表示类或对象"能做什么"
- 事件(Event): 类或对象通知其他类或对象的机制,为
C#
所特有
静态成员与实例成员:
- 静态成员在语义上表示它是"类的成员"
- 实例成员在语义上表示它是"对象的成员"
- 绑定指的是编译器如果把一个成员与类或对象关联起来
C#语言的基本元素
- 标记(Token)
- 关键字: C#本身使用的一些单词,不可被用于类、变量等
- 操作符: 加减乘除等操作符号
- 标识符: 类名、方法名、变量名
- 标点符号: 必须但不参与运算
- 文本
- 注释与空白
- 单行注释:
//
- 块注释:
/**/
- 文档注释:
///
- 单行注释:
类型、变量、方法
- 类型(
Type/Data Type
)- 数据存储在内存中的"型号"
- 小内存容纳大尺寸数据会丢失精确度、发生错误
- 大内存容纳小尺寸数据会导致浪费
- 编程语言的数据类型与数据的数据类型不完全相同
- 变量是存放数据的地方,简称数据
- 方法(函数)是处理数据的逻辑,可以称为(算法)
- 程序 = 数据 + 算法
数据类型所包含的信息:
- 存储此类型变量所需的内存空间大小
- 此类型的值可表示的最大、最小值范围
- 此类型所包含的成员(如方法、属性、事件等)
- 此类型由何基类派生而来
- 程序运行的时候,此类型的变量分配在内存的什么位置
- C#通过GC进行系统资源自动回收
- 此类型所允许的操作
Type | Range | Size |
---|---|---|
sbyte | -128 to 127 | 8-bit |
byte | 0 to 255 | 8-bit |
char | U+ 0000 to U+ffff | 16-bit |
short | -32,768 to 32,767 | 16-bit |
ushort | 0 to 65,535 | 16-bit |
int | -2,147,483,648 to 2,147,483,647 | 32-bit |
uint | 0 to 4,294,967,295 | 32-bit |
long | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | 64-bit |
ulong | 0 to 18,446,744,073,709,551,615 | 64-bit |
Type | Range | Size | Precision |
---|---|---|---|
float | ±1.5e-45 to ±3.4e38 | 32-bit | 7digits |
double | ±5.0e-324 to ±1.7e308 | 64-bit | 15~16 digits |
C#中的五大数据类型
- 类(如
Window
、Form
、Console
、String
) - 结构体(如
Int32
、Int64
、Single
、Double
) - 枚举(如
Visibility
) - 接口
- 委托
C#类型的派生体系
变量
什么是变量:
- 变量是用来存储数据的
- 变量 = 以变量名所对应的内存地址为起点,以其数据类型所要求的存储空间为长度的一块内存区域
- 变量表示存储位置,并且每隔变量都有一个类型,决定什么样的值能够存入变量
- 变量一种有7种:
- 静态变量
- 实例变量(成员变量,字段)
- 数组元素
- 值参数
- 引用参数
- 输出形参
- 局部变量
- 狭义变量指局部变量,因为其他种类的变量都有自己的约定名称,局部变量就是方法体(函数体)里声明的变量
- 变量的声明: 有效的修饰符组合(类型、变量名、初始化器)
值类型的变量:
- 以
byte/sbyte/short/ushort
为例 - 值类型没有实例,所谓的“实例”与变量合而为一
引用类型的变量与实例:
- 引用类型的变量与实例的关系: 引用类型变量里存储的数据是对象的内存地址
注:
-
局部变量在
stack
上分配内存 -
变量的默认值(一旦变量初始化好,该变量在内存中的所有bit刷成0)
-
常量
-
装箱和拆箱
int x = 100; object obj; obj = x; // 先将100这部分内容在栈上找到一块内存放入 // 在栈上分配obj所需内存 // 在堆上找一块内存空间,把100放进去,保存地址 // 然后将这部分堆的内存地址赋给栈中obj所在内存中 // 拆箱就是将obj在栈的内存地址中的地址取出,去堆中取数据
-
const
关键字修饰的变量不可改变
方法
方法的前身是C/C++语言的函数
方法是面向对象范畴的概念,在非面向对象语言中仍然称为函数
- 方法永远都是类或结构体的成员
- 方法是类或结构体最基本的成员之一
- 方法表示类或者结构体可以做什么事
- 方法的本质是数据+算法
使用方法的目的
- 隐藏复杂的逻辑
- 把大算法分解为小算法
- 复用
注: C#
和Java
不同,方法名使用大驼峰
构造器
- 构造器是类型的成员之一
- 狭义的构造器指的是"实例构造器"
构造器创建的内存原理
- 先在栈中找到位置存放对象的地址
- 在堆中找出位置存放对象中成员变量
- 将堆中的首地址赋给栈中对象的内存区域
方法的重载
- 方法的签名由方法的名称、类型形参的个数和它的每一个形参(按照从左到右的顺序)的类型和种类(值、引用或输出)组成,方法签名不包含返回类型
- 实例构造函数签名由它的每一个形参(按从左到右的顺序)的类型和种类(值、引用或输出)组成
- 重载决策(调用哪一个重载): 用于在给定了参数列表和一组候选函数成员的情况下,选择一个绝佳的函数成员来实施调用
类型转换
-
隐式类型转换
-
不丢失精度的转换
int x = int.MaxValue; long y = x;
// 从sbyte到short、int、long、float、double或decimal // 从byte到short、ushort、int、uint、long、ulong、float、double或decimal // 从short到int、long、float、double或decimal // 从ushort到int、uint、long、ulong、float、double或decimal // 从int到long、float、double或decimal // 从uint到long、ulong、float、double或decimal // 从long到float、double或decimal // 从ulong到float、double或decimal // 从char到ushort、int、uint、long、ulong、float、double或decimal // 从float到double // 从int、uint、long、ulong到float的转换以及从long或ulong到double的转换可能导致精度损失,但绝不会影响数值大小,其他的类型转换不会导致精度缺失
-
子类向父类的转换
class Animal { public void Eat() { Console.WriteLine("eat"); } } class Humen : Animal { public void Think() { Console.WriteLine("think"); } } class Student : Humen { public void Study() { Console.WriteLine("study"); } } //Student s = new Student(); //Humen h = s; //Animal a = h; //a.Eat(); //h.Eat(); //h.Think(); //s.Eat(); //s.Think(); //s.Study();
-
装箱
-
-
显式类型转换
-
有可能丢失精度(甚至发生错误)的转换,即
cast
uint x = 65536; ushort y = (ushort)x;
-
拆箱
-
使用
Convert
类 -
ToString
方法与各数据类型的Parse/TryParse
方法
-
-
自定义类型转换操作符
class Stone { public int Age; public static explicit operator Monkey(Stone stone) { Monkey m = new Monkey(); m.Age = stone.Age / 500; return m; } } class Monkey { public int Age; } //Stone stone = new Stone(); //stone.Age = 5000; //Monkey monkey = (Monkey)stone; //Console.WriteLine(monkey.Age);
操作符
- 操作符不能脱离与它相关的数据类型
运算符的优先级
- 可以使用圆括号提高被括起来的表达式的优先级
- 圆括号可以嵌套
同优先级操作符的运算顺序
- 除了带有赋值功能的操作符,同优先级操作符都是由左向右进行运算
- 带有赋值功能的操作符的运算顺序是由右向左
- 计算机语言的同优先级运算没有"结合律"
操作符详细说明
-
基本操作符
.
: 成员访问符f(x)
: 方法调用操作符a[x]
: 访问集合元素typeof
: 查看该类型的内部结构default
: 获取这个类型的默认值(是一个集合或者枚举的话,默认值是索引是0或者枚举值为0的元素)new
: 创建对象时使用,有一些不用加new
(语法糖衣)
// 自动推断类型 var person = new {Name = "XLrong", Age = "23"}; Console.WriteLine(person.Name);
class Student { public void Report() { Console.WriteLine("I am a student"); } } class CsStudent: Student { new public void Report() { Console.WriteLine("i am CS Student"); } }
checked
: 告诉程序要检查溢出
uint x = uint.MaxValue; uint y = checked(x + 1);
unchecked
: 不检查溢出delegate
: 已过时、Lambda
表达式将其替代sizeof
: 获取基本类型在内存中的字节数(可以在unsafe
的代码块中运行)->
:C#
中是有指针的,但是需要在不安全的上下文中操作
-
一元操作符:
&x
: 取地址操作符(需要不安全的上下文操作)*x
: 引用操作符(需要不安全的上下文操作)+
: 正-
: 负!
: 非~
: 求反,对一个二进制数进行按位取反++x
: 自增--x
: 自减(T)x
: 类型转换await
: 异步等待任务完成
-
乘法:
-
*
: 乘法、指针+y –y +0 –0 +∞ –∞ NaN +x +z –z +0 –0 +∞ –∞ NaN –x –z +z –0 +0 –∞ +∞ NaN +0 +0 –0 +0 –0 NaN NaN NaN –0 –0 +0 –0 +0 NaN NaN NaN +∞ +∞ –∞ NaN NaN +∞ –∞ NaN –∞ –∞ +∞ NaN NaN –∞ +∞ NaN NaN NaN NaN NaN NaN NaN NaN NaN -
/
: 除法+y –y +0 –0 +∞ –∞ NaN +x +z –z +∞ –∞ +0 –0 NaN –x –z +z –∞ +∞ –0 +0 NaN +0 +0 –0 NaN NaN +0 –0 NaN –0 –0 +0 NaN NaN –0 +0 NaN +∞ +∞ –∞ +∞ –∞ NaN NaN NaN –∞ –∞ +∞ –∞ +∞ NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN -
%
: 取余+y –y +0 –0 +∞ –∞ NaN +x +z +z NaN NaN x x NaN –x –z –z NaN NaN –x –x NaN +0 +0 +0 NaN NaN +0 +0 NaN –0 –0 –0 NaN NaN –0 –0 NaN +∞ NaN NaN NaN NaN NaN NaN NaN –∞ NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
-
-
加法:
+
: 加、字符串连接、委托-
: 减
-
位移操作符:
<<
: 二进制数据左移>>
: 二进制数据右移
-
关系比较符:
<
:>
:<=
:>=
:is
: 判断两个对象是否是同一个类(子类 is 父类也是true)as
: 可以当作强制转换使用
-
相等:
==
:!=
:
-
逻辑与:
&
-
逻辑异或:
^
-
逻辑或:
|
-
条件与:
&&
-
条件或:
&&
-
null合并
:??
// 可空类型 Nullable<int> a = null; int? x = null; int y = x ?? 1; // 如果是null赋值1
-
条件:
?:
(三目表达式) -
赋值和
Lambda
表达式:+=
: