Skip to content

Latest commit

 

History

History
766 lines (355 loc) · 10.8 KB

C#.md

File metadata and controls

766 lines (355 loc) · 10.8 KB
  • 使用的是大驼峰的命名法

.net

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者

  1. valueType, 结构体是作为值类型的, 申明的时候就有空间了, 不可继承
  2. 引用类, 可继承
  • 任何变量需要被初始化过值之后才可以访问, 但是可以写入(在for嵌套体中的初始化不被作为一个合格的初始化, 但是块内容中的初始化是合格的)

使用var

暗示变量的类型

  • 使用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);
  • 使用文本插值的时候,可以插入一个数字类型.

  • @$符号可以一起使用

隐式类型转换

使用+连接字符串和数字类型的时候,会把数字类型转换成为字符串类型相加

转换浮点数到数字类型的时候,小数部分会被截断

decimal

十进制表示的数字

类型转换

使用int.Parse, 可能存在报错

使用 int.TryParse尝试类型转换

返回值是是否正确转换, 需要传入一个结果值(out参数)

输入

String str = Console.ReadLine();
Console.WriteLine(str);

读入一行

转换

使用ConvertToInt32

使用intParse方法

值类型(value type)

简单变量, 指向的内存就存放着内容

引用类型(reference type)

存放的是复杂变量

  • 使用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返回值.

  • 返回参数使用括号包裹, 可以返回多个, 相当于是()元组, 接受的时候使用解析的方式打开

readonlyconst

const在编译的时候, 会被替换, 类似于define

readonly编译之后依旧存在

if

  • 不可以直接把int变量作为判断的条件, 不会自动把int转换为bool
  • &&&都是and, &没有短路效果

Object

所有的类都从Object中继承的

ToString方法

工具类

Array

引用类型, 从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];
  • arrLength是3*4, 总的长度
  • 使用GetLength(),传入的参数是第几维度.

使用foreach输出二维数组的时候, 把二维压成了一维

锯齿数组

int[][] arr = new int[3][];
arr[0] = new int[4];
arr[1] = new int[5];
  • 对于0维可以使用GetLength, 对于其他不确定长度的维度, 不可以使用

string

使用的是unicode(使用2字节表示)

使用CompareTo进行比较

str[0]='a'错误, 对于索引器(只读)是不可以修改的

  • 字符串是不可变的, 需要接受返回值

  • 字符串的修改操作是低效的

  • 需要对字符串的修改操作很多的时候, 使用StringBuilder实现

Pad和Trim做的是相反的操作

操作

add: +

修改: replace, trim, pad

切分: substring, spilt

使用$来快速格式化输出

$"{number,10:F5}"占十个位置, 浮点数部分占五个位置

Char

是一个结构体struct

Random

int number = random.Next(10,100);
  • 左闭合右开放

DateTime

显示自己的时间信息

元组

使用()

(string name, int number) person = ("xuhe", 1);
person.name;
  • 也是一种值类型

class

internal class(默认): 同一个程序集中就可以访问, 是同一个项目.

data

instance fields,cont,inner class,static fields,readonly

  • 存在内部类
  • 只有构造函数可以设置readonly的变量
  • 可以通过设置setter但是不设置getter, 让一个变量成为readonly

method

包含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;
}
  • 当执行派生类的构造函数的时候, 会自动调用基类的无参构造函数.

getter/setter

public int x{
    set{
        
    }
    private get{
        
    }
}

继承

字段和属性都是可以继承的

  • 构造函数不可继承, 有static属性的.

override

存在override关键字

public override func(){}

virtual

虚函数

  • 需要virtualoverride配合使用, 才有多态的效果. 如果不使用, 那么是hide效果

  • 可以给property使用

abstract

有抽象方法就是抽象类

抽象类无法被继承

  • 抽象方法只有申明, 没有实现, 但是虚方法可以有实现

sealed

被继承了也不可以被重写的方法

  • sealed是对下的, override是对上的, 所以2者可以共存
  • sealedabstract/virtual不可以共存

不可变类

注意, 行为是不可修改的

字段: private(不可以是protected)

属性: 没有set

方法: 不可以set, 返回一个new的新对象

给类添加sealed, 不可以被继承可以防止子类修改行为

调用基类的方法

使用base调用基类的操作, 比如base()无参构造函数, base.func()基类方法

object类

使用ObjectGetType方法

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个实例是不是同一个.

interface类

不可以存在变量, 但是可以存在属性和函数

  • 默认public, 不可以使用private, 但是可以使用protectedinternalstatic(需要实现).

protected是给子类用的

  • 接口类的函数可以被实现, 当添加接口类的功能的时候, 直接在接口类的函数中实现它, 可以保证不需要大量重写实现类的代码

  • 可以多继承

显式实现和隐式实现

    double IShape.GetArea() // 显式实现 GetArea() 方法
    {
        return Width * Height;
    }

    double IShape.GetPerimeter() // 显式实现 GetPerimeter() 方法
    {
        return 2 * (Width + Height);
    }
  • 显式的继承会使得只能使用接口类来调用这个功能, 无法使用子类直接调用

equals方法

默认比较地址, 如果是值类型, 那么比较内容

不适用泛型的时候, 接受的参数是object, 需要手动转换类型

  • 比较的时候, 只在乎返回值的正负, 不会在意绝对值的大小

如果使用泛型的Comparable实现, 接受的值的类型是确定的

sort方法

使用CompareTo来自IComparable继承的

使用Compator的实现

使用重写之后的运算符, 大于号和小于号需要成对的重写, 但是加号减号不是

重写的运算符需要是publicstatic.

ArrayList

没有指定类型的数组可以存储任何类型的数据, 但是存到内部的内容是object, 所以, 使用的时候需要unboxing

放入数据的时候: 先把数据转换为引用类型, 然后放入

指定类型的数组可以直接使用.

Delegate代理

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