- 使用的是大驼峰的命名法
dotnet = FCL + CLR
framework class library 类似JAVA中的JDK
common language runtime 类似JAVA的JVM
- 面向对象
- 事件驱动
- 存在GC
WPF: 界面可视化编程
C# -> CIL(中间语言) -> JIT
使用decimal
,float
,double
-
默认使用的是
double
-
int是一个结构体, 在CIL中叫做int32
-
全部的变量从
Object
继承, 才可以使用CLR管理内存
继承
Object
的分成2者
- valueType, 结构体是作为值类型的, 申明的时候就有空间了, 不可继承
- 引用类, 可继承
- 任何变量需要被初始化过值之后才可以访问, 但是可以写入(在
for
嵌套体中的初始化不被作为一个合格的初始化, 但是块内容中的初始化是合格的)
暗示变量的类型
- 使用
var
的时候,需要初始化.
不存在\
符号的转义或者别的内容
使用@
运算符
// To generate Japanese invoices:
// Nihon no seikyū-sho o seisei suru ni wa:
Console.Write("\n\n\u65e5\u672c\u306e\u8acb\u6c42\u66f8\u3092\u751f\u6210\u3059\u308b\u306b\u306f\uff1a\n\t");
// User command to run an application
Console.WriteLine(@"c:\invoices\app.exe -j");
使用$
符号实现
string name = "xuhe";
string str = $"hello {name}";
Console.Write(str);
-
使用文本插值的时候,可以插入一个数字类型.
-
@
和$
符号可以一起使用
使用+
连接字符串和数字类型的时候,会把数字类型转换成为字符串类型相加
转换浮点数到数字类型的时候,小数部分会被截断
十进制表示的数字
使用int.Parse
, 可能存在报错
使用 int.TryParse
尝试类型转换
返回值是是否正确转换, 需要传入一个结果值(out参数)
String str = Console.ReadLine();
Console.WriteLine(str);
读入一行
使用Convert
的ToInt32
使用int
的Parse
方法
简单变量, 指向的内存就存放着内容
存放的是复杂变量
- 使用CLR自动的垃圾回收
使用using <package name>
导入
- 命名空间可以嵌套
包含instance variables
,function
,static
,const
,properties(setter/getter)
属性是一个语法糖(实现了getter
/setter
)
public int X{
get {
return x;
}
set {
x = value;
}
}
- 不能和变量同名
className.X = 1;
public int x{ get; set; }
- 把实际的变量存在一个不显示的地方
不允许写入的做法
public int x{ get; private set; }
- 最好使用统一的属性来操作
public class_name {
}
同时里面的属性会自动被赋值
- 需要表明
public
public class_name: this(xx,xx) {}
在调用空参数构造函数的时候, 复用有参构造函数
~class_name() {}
- 不需要
public
- 一般不写, 可能阻止垃圾回收机制
不可访问
访问级别是internal
在同一个程序集中才可以访问
使用params
参数实现
static int func(params int[] n){}
func(1);
func(1,2);
func([1,2,3]);
默认传递的是值
引用传递的也是值, 传递的是地址值
引用类型的参数
public void func(ref int a){}
func(ref a);
public void func(out int a) {}
func(out a);
-
ref
需要变量被初始化, 但是out
可以不需要初始化 -
out
传入的参数不可以直接被print
, out是为了被赋值的 -
返回值可以是
ref int
, 但是不可以是out int
返回值. -
返回参数使用括号包裹, 可以返回多个, 相当于是
()
元组, 接受的时候使用解析的方式打开
const
在编译的时候, 会被替换, 类似于define
readonly
编译之后依旧存在
- 不可以直接把int变量作为判断的条件, 不会自动把
int
转换为bool
&
和&&
都是and,&
没有短路效果
所有的类都从Object
中继承的
有ToString
方法
引用类型, 从Array继承过来的信息
int[] a = new int[10];
-
没有的初始值的new, 会使用默认值0
-
使用参数
Length
检查长度
初始化
int[] arr = {1, 2, 3};
int[] arr = new int[]{1, 2};
- 当初始化指定的长度和传入的参数的值个数不一样的时候, 会错误
循环数组
使用
for
直接遍历每个数组的长度, 作为下标访问
使用
foreach
遍历(不可修改值)
foreach(int i in arr){
}
使用工具类的静态方法实现二分搜索, 实现排序
使用,
int[,] arr = new int[3,4];
arr
的Length
是3*4, 总的长度- 使用
GetLength()
,传入的参数是第几维度.
使用foreach
输出二维数组的时候, 把二维压成了一维
锯齿数组
int[][] arr = new int[3][];
arr[0] = new int[4];
arr[1] = new int[5];
- 对于0维可以使用
GetLength
, 对于其他不确定长度的维度, 不可以使用
使用的是unicode
(使用2字节表示)
使用CompareTo
进行比较
str[0]='a'
错误, 对于索引器(只读)是不可以修改的
-
字符串是不可变的, 需要接受返回值
-
字符串的修改操作是低效的
-
需要对字符串的修改操作很多的时候, 使用
StringBuilder
实现
Pad和Trim做的是相反的操作
add: +
修改: replace, trim, pad
切分: substring, spilt
使用$
来快速格式化输出
$"{number,10:F5}"
占十个位置, 浮点数部分占五个位置
是一个结构体struct
int number = random.Next(10,100);
- 左闭合右开放
显示自己的时间信息
使用()
(string name, int number) person = ("xuhe", 1);
person.name;
- 也是一种值类型
internal class(默认): 同一个程序集中就可以访问, 是同一个项目.
instance fields,cont,inner class,static fields,readonly
- 存在内部类
- 只有构造函数可以设置readonly的变量
- 可以通过设置setter但是不设置getter, 让一个变量成为readonly
包含instance method,static method,constructor,destructor,property,overloaded operation,index
-
默认是
private
. -
使用析构函数会造成垃圾回收的延后, 所以, 如果需要手动的清除, 设置一个
Dispose
函数
在使用的时候, 使用
using(var a = new var()){}
的语法糖或者显式的调用
Dispose
函数
构造方法之间的调用
public class_name(): this(1){
}
public class_name(int number){
//
}
调用的时候可以使用{}
来初始化
class_name a = new class_name{
var1 = 1;
}
- 当执行派生类的构造函数的时候, 会自动调用基类的无参构造函数.
public int x{
set{
}
private get{
}
}
字段和属性都是可以继承的
- 构造函数不可继承, 有static属性的.
存在override
关键字
public override func(){}
虚函数
-
需要
virtual
和override
配合使用, 才有多态的效果. 如果不使用, 那么是hide效果 -
可以给
property
使用
有抽象方法就是抽象类
抽象类无法被继承
- 抽象方法只有申明, 没有实现, 但是虚方法可以有实现
被继承了也不可以被重写的方法
- sealed是对下的, override是对上的, 所以2者可以共存
sealed
和abstract
/virtual
不可以共存
注意, 行为是不可修改的
字段: private(不可以是protected)
属性: 没有set
方法: 不可以set, 返回一个new的新对象
给类添加sealed, 不可以被继承可以防止子类修改行为
使用base
调用基类的操作, 比如base()
无参构造函数, base.func()
基类方法
使用Object
的GetType
方法
var.GetType() == typeof(class_name);
也可以写成
(var is class_name)
类型转换, 直接使用强制的类型转换写作class_name var = (class_name)old_var
或者使用var = old_var as class_name
, 如果转换失败, 返回null
深度赋值实现
- C#中的赋值, 对于复杂对象是赋值引用
Equals
方法默认是比较地址, 看2个实例是不是同一个.
不可以存在变量, 但是可以存在属性和函数
- 默认public, 不可以使用private, 但是可以使用
protected
和internal
和static(需要实现)
.
protected是给子类用的
-
接口类的函数可以被实现, 当添加接口类的功能的时候, 直接在接口类的函数中实现它, 可以保证不需要大量重写实现类的代码
-
可以多继承
double IShape.GetArea() // 显式实现 GetArea() 方法
{
return Width * Height;
}
double IShape.GetPerimeter() // 显式实现 GetPerimeter() 方法
{
return 2 * (Width + Height);
}
- 显式的继承会使得只能使用接口类来调用这个功能, 无法使用子类直接调用
默认比较地址, 如果是值类型, 那么比较内容
不适用泛型的时候, 接受的参数是object
, 需要手动转换类型
- 比较的时候, 只在乎返回值的正负, 不会在意绝对值的大小
如果使用泛型的Comparable实现, 接受的值的类型是确定的
使用CompareTo
来自IComparable
继承的
使用Compator
的实现
使用重写之后的运算符, 大于号和小于号需要成对的重写, 但是加号减号不是
重写的运算符需要是
public
和static
.
没有指定类型的数组可以存储任何类型的数据, 但是存到内部的内容是object, 所以, 使用的时候需要unboxing
放入数据的时候: 先把数据转换为引用类型, 然后放入
指定类型的数组可以直接使用.
delegate int MyDelegate(string message);
static int PrintMessage(string message)
{
Console.WriteLine(message);
return message.Length;
}
MyDelegate myDelegate = PrintMessage;
同一系列返回值和传入参数的函数作为一个系列, 可以把实例当成一个函数来使用
- 可以使用匿名函数赋值
int add(int x, int y) => x+y;
可以使用+
来多个方式调用, 返回值是不稳定的.
本质调用delegate的实现: 使用invoke
方法实现, 调用delegate_name.invoke