C#
基本特点
- 面向对象
语法特性
变量
- 值类型(数字):
- 整数: byte, sbyte, short, ushort, long, ulong, int, uint, char
- 十进制: decimal
- 浮点: float, double
- 其它: bool
- 址
- string(只能用双引号)
- object
- dynamic
- null
- 指
- point
类型转换
隐式
byte tmp = 1;
int res = tmp;
显式(pure)
byte tmp = 1;
int res = (int)tmp;
显式(Convert, Parse, TryParse)
int tmp = 32;
string res = Convert.ToString(tmp);
string res2 = tmp.ToString();
double res3 = double.parse(tmp);
bool isSuccess = double.TryParse(tmp);
IO
基础IO
string userInput = Console.ReadLine();
Console.WriteLine(userInput);
常量
定义与使用方法
const int num = 32;
字符串常量
string text = "xxx";
string textTrans = @"xxx\txxx";
运算符
运算符逻辑与JavaScript类似, 不同的是c#全等运算就是==
基础运算符
算术运算: + - ++ -- % / *
关系运算: == != >= <= > <
逻辑运算: || && !
赋值运算: = += -= *= /= %= <<= >>= &= ^= |=
特殊运算符
sizeof()
typeof()
?:
& *
is
as ( 强制类型转换, 失败不会抛异常
流程控制
与大部分语言类似: if类, switch类, 三元表达式
循环
与大部分语言类似, 有for和while类循环, 以及foreach:
- while & do whilecacc
- for
- foreach
语言特性
方法
方法的语法组成
<access specifler> <return type> <method name> (parameter list) {
method body
}
传参
传参分为三种:
- 值
- 址
- 输出
值传递与其它语言类似, 址传递需要使用ref进行声明
public void xMethod(ref numRef){
numRef += 1;
}
int num = 32;
xMethod(ref num);
使用输出参数可以从函数中返回两个值, 其会把方法的输出数据赋值给自己, 其它方面类似引用参数
public void outputValue(out num){
num = 100;
}
int tmp = 32;
outputValue(out tmp)
可空类型
单问号(?), 意思是Nullable类型
int? tmp = 3;
等同于
Nullable<int> tmp = new Nullable<int>(3);
声明默认值
int tmp; // 默认值为0
int? tmp; 默认值为null
int? tmp = new Int?();
声明一个null变量
<data type>? <var name> = null;
合并运算符 (??) 若前者值为null, 啧返回第二个, 效果类似于 || 或判断是否为空的三元表达式
int? num = null;
int num2 = num ?? 100;
// or
int num3 = (num == null) ? 100 : num
数组
数组是一种用于存储固定大小、同一类型元素的集合, 其在c#中为引用类型, 需要通过new来赋值
- 类型安全
- 固定长度
- 索引访问
- 多维
数组被创建时, c#会根据不同的数据类型赋予默认值, 如int[]元素默认值为0 数组作为参数传递时, 传递地址
<data type>[] <data name> = new <data type>[length];
// 赋值字面量
int[] tmp = {1, 2, 3, 4}
二维数组 语法上略有不同, 需要在创建时指定行列数量
// ,将空间一分为二, 代表data type为二维数组
string [,] names;
int [,] nums = new Int[2, 3]{
{0, 1, 2},
{3, 4, 5}
}
// 访问
int aimNum = nums[0, 2]
交错数组 交错数组是一维数组
int[][] nums = new int[2][]{new int[]{1,2,3}, new int[]{4,5,6}};
Array类 Array为数组基类, namespace为System: System.Array
Properties
- Length
- Rank 获取维度
- IsFixedSize
- IsReadOnly
- IsSynchronized 是否线程安全
- SyncRoot 同步多线程下数组访问对象
Methods
- Clear 范围内设置为0 false null的其中一个
- Copy(Arr, Arr, Len) A复制到长度为Len的B
- CopyTo(Arr, Len)
- GetLength / GetLongLength
- GetLowerBound / GetUpperBound 维度下 / 上界
- GetType
- GetValue(index) / SetValue(Obj, index) 获取 / 设置index位置的值
- IndexOf(Arr, Obj)
- Sort(Arr) / Reverse(Arr)
- ToString()
- Clone() 浅拷贝@
- Exist(Arr, x=>x==xxx) -> bool
- AsReadOnly()
- Fill()
- ForEach()
- TrueForAll(Arr, x=>x==xxx)
- Resize(Arr, newSize)
- BinarySearch(Arr, value)
- Find类
字符串
基础使用
string tmp = "";
string[] tmp = {"1", "2", "3"}
Format使用
DateTime waiting = new DateTime(2024, 10, 24, 00, 00, 00)
string time = String.Format("{0:t} on {0:D}")
Properties
- Chars
- Length
Methods
- Compare
- Concat
- Contains
- Copy
- CopyTo
- StartsWith / EndsWith
- Equals
- indexOf
- Insert
- IsNullOrEmpty
- Join
- Remove
- Replcae
- Split
- Trim
- ToLower / ToUpper
- ToCharArray
- SubString
结构体
结构体在c#中是轻量级的数据类型, 适用于定义较为简单的数据
- 可实现多个接口
- 可以省略new, 初始化之后才会被赋值
- 分配于栈
- 值类型
结构体与类的区别
- 结构体是Value Type; 类是Reference Type
- 继承与多态: 结构体不支持, 类支持
- 构造函数: 结构体不能有无参的构造函数, 类可以
- 存储与传递:
- 结构体是值, 类是址;
- 结构体存储于栈, 类存储于堆;
- 结构体更加轻量化, 类涉及更多的内存开销与管理
- 结构体不可为null, 需要设置为Nullable<T>或T?; 类可以为null
枚举
用法
enum MODE {dev, prod, test}
类
特性
- 类的默认访问符为inernal; 成员的默认访问符为private
- 成员即为对象的属性, 默认情况下保持私有以实现封装
语法
<access specifiler> class {}
构造函数
- 与类名完全相同
- 无返回类型
构析函数 特点:
- 无返回
- 无参数
- 不可被继承与重载
作用: 结束程序前释放资源 使用: 构造函数前添加~
~<Construct Function Name>(){}
静态成员 可以使用static将成员定义为静态, 即便有多个类的实例被创建, 其静态成员唯一
封装 访问修饰符, 权限逐步缩小
- public
- internal / protected internal
- protected
- private
继承与多态 C#支持单继承与接口的 多继承 基类也称作父类, 派生类也称作子类
为什么可继承的语言语法中, 子类的构造函数旺旺需要调用父类的构造函数?
子类对象依赖父类, 所以子类对象需要在父类对象创建后才能被创建
类继承的使用
public class Shape {}
public class Rectangle: Shape{
public Shape():base(){}
}
接口继承的使用
interface BaseInterface {
void MethodA();
}
interface NormalInterface: BaseInterface{
void MethodB();
}
// 类对接口的implement, 与继承的写法相同
class ImplementClass: NormalInterface{
public void MethodA(){...}
public void MethodB(){...}
}
接口的多继承 使用
interface InterfaceA {...}
interface InterfaceB {...}
class ImplementClass: InterfaceA, InterfaceB{...}
多态的类别
- 静态多态性(overload): 编译时
- 动态多态性(abstrct & virtual): 运行时
静态: return type必须相同, 才可以说是单个方法的重载
public class TestStatic{
public void test(){}
public void test(int num){}
}
动态 (!!!没搞懂)
运算符重载 (略)
接口
通常接口名以I开头 使用
interface IName{
<access specifiler> <return type> <name>(); // for method
<access specifiler> <data type> <name>; // for regular data
}
命名空间
诞生原因: 区分同名标识符 特点:
- 可嵌套(使用.访问内嵌namespace)
- 当A.xxx.method()与B.xxx.method被同一个文件导入后, 则系统会无法确认具体使用哪个方法
using System;
namespace N1{...}
namespace N2{...}
class Test{
// 互不干扰
N1.method();
N2.method();
}
using(包导入) 基本使用
using System;
using N1;
using N2;
class Test{
public void run(){
// 全称为System.Console.WriteLine(); 使用using XXX相当于把XXX包含的所有标识符都导入至当前文件 Console.WriteLine("RUN");
}
}
导入静态方法(using static)
using static System.Math;
Alias
using alias = OutterNamespace.InnerNamespace;
实例绑定
using (
int predefinedData = 32;
)
预处理指令
条件编译 #define #undef #if #elif #else #endif
日志 #warning #error
可读性 #region #endregion
其它 #line #pragma #nullable
正则表达式
(略)
异常处理
try catch finally
try{}
catch(Exception e){}
finally{}
异常类 IO: System.IO.IOException out of range: System.IndexOutOfRangeException null object: System.NullReferenceException zero: System.DivideByZeroException cast: System.InvalidCastException memory: System.OutOfMemoryException stack: System.StackOverflowExceptio
文件读写
binary data: BinaryReader / BinaryWriter
path: Path
buffer: BufferedStream StreamReader / StreamWriter
str: StringReader / StringWriter
dir: Directory / DirectoryInfo
file: File / FileInfo / FileStream
memory: MemoryStream
其它 DriveInfo
文件读写 文件流 / 基础文件读写 (FileStream) 参数
- FileMode:
- Append
- Create / CreateNew
- Open / OpenOrCreate
- Truncate
- FileAccess:
- Read / Write / ReadWrite
- FileShare
- Inheritable
- None
- Read / Write / ReadWrite
- Delete
FileStream file = new FileStream('test.csv', FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read)
文本文件读写 (StreamReader / StreamWriter) (略)
二进制文件读写 (BinaryReader, BinaryWriter)
Windows FS
string dirPath = @"D:\TestDir";
string filePath = @"D:\TestDir\TestFile.txt";
Console.WriteLine("<<<<<<<<<<<{0}>>>>>>>>>>", "文件路径");
//获得当前路径
Console.WriteLine(Environment.CurrentDirectory);
//文件或文件夹所在目录
Console.WriteLine(Path.GetDirectoryName(filePath)); //D:\TestDir
Console.WriteLine(Path.GetDirectoryName(dirPath)); //D:\
//文件扩展名
Console.WriteLine(Path.GetExtension(filePath)); //.txt
//文件名
Console.WriteLine(Path.GetFileName(filePath)); //TestFile.txt
Console.WriteLine(Path.GetFileName(dirPath)); //TestDir
Console.WriteLine(Path.GetFileNameWithoutExtension(filePath)); //TestFile
//绝对路径
Console.WriteLine(Path.GetFullPath(filePath)); //D:\TestDir\TestFile.txt
Console.WriteLine(Path.GetFullPath(dirPath)); //D:\TestDir
//更改扩展名
Console.WriteLine(Path.ChangeExtension(filePath, ".jpg"));//D:\TestDir\TestFile.jpg
//根目录
Console.WriteLine(Path.GetPathRoot(dirPath)); //D:\
//生成路径
Console.WriteLine(Path.Combine(new string[] { @"D:\", "BaseDir", "SubDir", "TestFile.txt" })); //D:\BaseDir\SubDir\TestFile.txt
//生成随即文件夹名或文件名
Console.WriteLine(Path.GetRandomFileName());
//创建磁盘上唯一命名的零字节的临时文件并返回该文件的完整路径
Console.WriteLine(Path.GetTempFileName());
//返回当前系统的临时文件夹的路径
Console.WriteLine(Path.GetTempPath());
//文件名中无效字符
Console.WriteLine(Path.GetInvalidFileNameChars());
//路径中无效字符
Console.WriteLine(Path.GetInvalidPathChars());
进阶属性
Attribute: 特性 / 元信息 Reflection: 反射 Property: 属性(定义类成员而非方法的访问和设置, 即访问器, 用于隐藏字段较多)
public void Demo(){
get {
return xxx;
}
set {
xxx = ooo;
}
}
// 自动实现
public string GetName {get; set;}
// 只读; 只写同理
public string GetName {get;}
// 计算属性 computed
public string GetDynamic {
get {
return xxx + ooo;
}
}
// abstract
public abstract string Name {get; set;}
索引器: 与大部分语言相同, c#可以自定义索引器
委托
委托是类, 是用来包裹对应函数的外衣 需要满足的条件
- return type 为空
- params 为空
原始用法
// 声明
delegate <return type> <delegate-name> <parameter list>
进阶用法
// 无返回值使用action
Action<T> action = new Action<T>();
action()
// 有返回值使用function
var Func<T> func = new Function<T>();
var res = func();
var Func func = ()=>{
return xxx;
}
func()
事件
集合 Collection
用于存储和检索的类
- Stack: Stack
- Queue: Queue
- List: ArrayList; SortedList
- Hash Table: HashTable
- Array: BitArray
泛型 Generic
与TS类似;c#有泛型委托与泛型约束 使用
// 用于类
class Test <T>{}
// 用于成员
public T Test(){}
// 用于参数
...(T paramDemo){}
匿名函数
Lambda表达式 与js类似
delegate void NumberChanger(int n);
NumberChanger nc = x => Console.WriteLine($"Lambda Expression: {x}");
匿名方法
// 声明
delegate void Method();
// 实现
Method method = Method(){
...
}; // 末尾要加;
不安全代码
通过unsafe修饰符标记的代码会允许使用指针变量, 这种代码称为不安全代码;
public static unsafe void Main(string[] args){
int num = 32;
int* p = #
}
对不安全代码进行编译时, 需要追加/unsafe参数;VS中可能需要先启用不安全代码才能使用
csc /unsafe xxx.cs
c#中的变量受GC影响, 可能会在运行时更改内存地址, 此时需要指定变量内存地址固定, 这时的指针变量才有意义;或者采取另一种方法: 将变量分配到堆栈内存上
fixed()
多线程
类: System.Threading.Thread 状态:
- 未启动(创建实例后, Start之前)
- 就绪
- 不可运行(调用了Sleep或Wait, IO阻塞)
- 结束(dead)
主线程 c#启动时, 主线程会被自动创建出来, 所以获取主线程就是在获取当前线程
using System.Threading;
...
Thread th = Thread.CurrentThread;
th.Name = "MainThread";
Thread类 属性
- Name
- Priority
- ThreadState
- ManagedThreadId
- IsAlive / IsBackground / IsThreadPoolThread
- CurrentContext
- CurrentCulture
- CurrentPrincipal
- CurrentThread
- CurrentUICulture
- ExecutionContext
方法
- Abort 终止线程
- ResetAbort 取消Abort请求
- Start 开始线程
- Sleep 暂停线程
- Interrupt 终端在WaitSleepJoin状态的线程
- Join 阻塞线程
- BeginCriticalRegion / EndCriticalRegion
- ...