cs-learning

C#数据类型

值类型

类型 描述 范围 默认值
bool 布尔值 True或False False
byte 8位无符号整数 0到255 0
sbyte 8位有符号整数 -128到127
char 16位Unicode字符 U +0000 到U +ffff ‘\0’
decimal 128位精确的十进制值,28~29有效位数 (-7.9 * 10 ^ 28)/10 ^ (0 到 28) 0.0M
short
ushort
int
uint
double
float
long
ulong

引用类型

Object类型

对象(Object)类型是C#通用类型系统中所有数据类型的终极基类.
Object类可以被分配给任何其他类型的值.但是在分配之前,需要先进行类型转换.
当一个值类型转换为对象类型时,被称为装箱,当一个对象类型转换为值类型时,被称为拆箱

1
2
object obj;
obj = 100; // 这是装箱

Dynamic类型

动态(Dynamic)类型变量可以存储任何类型

1
dynamic a = 20;

String类型

字符串(String)类型允许给变量分配任何字符串值.
C#的字符串只能是双引号,不能单引号.
字符串前面加@,则该字符串的转义符()将被当做普通字符对待(就像python字符串前面加r似的)

1
2
3
4
5
Console.WriteLine("a\nb");
// a
// b
Console.WriteLine(@"a\nb");
// a\nb

指针类型

**指针类型(Pointer types)**变量存储另一种类型的内存地址.
当一个代码块使用 unsafe 修饰符标记时,C#允许在函数中使用指针变量。不安全代码或非托管代码是指使用了指针变量的代码块。

1
char* cptr;

类型转换

类型转换从根本上说是类型铸造,或者说是把数据从一种类型转换到另一种类型.
在C#中,类型转换有两种形式:

  • 隐式类型转换
    这些转换是C#默认的以安全方式进行的转换,不会导致数据的丢失.如,从小的整数转换为大的整数,从派生类转换为基类
  • 显式类型转换
    即强制类型转换.需要强制转换运算符,可能会造成数据丢失

类型转换方法

1
2
3
4
int i = 1;
bool b = Convert.ToBoolean(i);
Console.Write(b);
// True

循环

foreach循环

使用foreach可以迭代数组或者一个集合对象

1
2
3
4
5
6
int[] i = new int[] {114, 514, 1919, 810};
foreach (var a in i)
{
Console.Write(a);
// 1145141919810
}

封装

Public

Private

Protected

允许子类访问它的基类的成员函数和成员变量.

Internal

允许一个类将其成员变量和成员函数暴露给当前函数中的其他函数和对象

方法

定义

1
2
3
4
<Access Specifier> <Return Type> <Method Name>(Parameter List)
{
Method Body
}

参数传递

方式 描述
值参数 复制参数的实际值给函数的形参.
实参和形参使用的内存不同.
形参值改变时不会影响实参.
引用传递 复制参数内存位置的引用给形参.
当形参值改变时,会改变实参
输出参数 这种方式可以返回多个值(?)

按值传递

传参的默认方式.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void swap(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}

static void Main(string[] args)
{
Program program = new Program();
int x = 5, y = 6;

Console.WriteLine($"{x},{y}");
// 5,6

program.swap(x, y);

Console.WriteLine($"{x},{y}");
// 5,6
}

按引用传递

在C#中,使用ref关键字声明引用参数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void swap(ref int x, ref int y)
{
int temp;

temp = x;
x = y;
y = temp;
}

static void Main(string[] args)
{
Program program = new Program();
int x = 5, y = 6;

Console.WriteLine($"{x},{y}");
// 5,6

program.swap(ref x,ref y);

Console.WriteLine($"{x},{y}");
// 6,5
}

按输出传递参数

return语句可用于只从函数中返回一个值.但是,可以使用*输出参数来从函数中返回多个值.
输出参数会把方法输出的数据赋值给自己,其他方面与引用参数类似.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public int divmod(int a, int b, out int c)
{
int div = (int) (a / b);
int mod = a % b;
c = mod;
return div;
}

static void Main(string[] args)
{
Program program = new Program();
int x = 11, y = 3;
int div, mod;
div = program.divmod(x, y, out mod);
Console.WriteLine($"{div},{mod}");
// 3,2
}

可空类型

C#提供了一个特殊的数据类型,nullable类型,可空类型可以表示其基础值正常范围内的值,在加上一个null值.
例如Nullable,读作可空的Int32.
在处理数据库和其他包含可能未赋值的元素的数据类型时,将null赋值给数值类型和布尔型的功能特别有用.

可空类型的声明

可空类型的声明语法如下:

1
Int32? x;

Null合并运算符

Null合并运算符用于定义可空类型和引用类型的默认值.
Null合并运算符为类型转换定义了一个预设值,以防可空类型为Null.
Null运算符吧操作数类型隐式转换成另一个可空(或不可空)的值类型的操作数的类型.
如果第一个数为null,则运算符返回第二个操作数的值,否则返回第一个操作数的值.

1
2
3
4
5
6
7
8
9
int? a = 1;
int x = a ?? 233;
Console.WriteLine(x);
// 1

int? b = null;
int y = b ?? 233;
Console.WriteLine(y);
// 233

数组

数组声明

1
int[] a = new int[10];

数组赋值

数组声明时赋值

声明时赋值可以省略数组大小.

1
2
int[] a = new int[4] {0, 1, 2, 3};
int[] b = new int[] {0, 1, 2, 3};

数组引用赋值

1
2
int[] a = new int[4];
a[1] = 2;

复制数组

这种情况下,目标和源会指向相同的内存位置.

1
2
int[] a = new int[] {0, 1, 2, 3};
int[] b = a;

遍历数组

1
2
3
4
5
int[] a = new int[] {0, 1, 2, 3};
foreach (int v in a)
{
Console.WriteLine(v);
}

结构体

1
2
3
4
5
6
7
8
9
10
struct A
{
public int a;
public String s;

public int func(int x)
{
return x + a;
}
};

枚举

枚举是一组命名整型常量.枚举是使用enum关键字声明的.
C#枚举是值类型,即 枚举包含自己的值,且不能继承或传递继承.

1
2
3
var x = A.a;
Console.WriteLine(x);
// 0

析构函数

在程序结束前执行(大概?)

1
2
3
4
5
6
7
class A
{
~A()
{
Console.WriteLine("Cancel.");
}
}

类的静态成员

使用static关键字把类成员定义为静态.
当我们声明一个类成员为静态时,无论多少个类被创建,只会有一个改进静态类成员的副本.
静态变量用于定义常量,他们的值可以通过直接调用类而不需要创建类的实例来获取(无法通过实例来访问,只能通过类访问).
静态变量可以在成员函数或类的定义外部进行初始化,也可以在类的定义内部进行初始化.