第一章
1.字符串是不可变的:所有string类型的数据,都不可变,也可以说是不可修改的,不能修改变量最初引用的数据,只能对其重新赋值,让其指向内存中的一个新位置。
第二章
2.1 预定义类型或基本类型:
C#语言的基本类型包括8种整数类型,2种用于科学计算的二级制浮点类型,1种用于金融计算的十进制浮点类型,1种布尔类型以及一种字符类型。
2.1.1 整数类型:

要注意int32的范围,如果是要保存10位以上的数字编号的时候,要么使用string,要么使用int64,因为int32只能保存到10位,22 0000 0000都保存不了。
2.1.2 浮点类型:
有可能一个数被定义为0.1但是只是很接近0.1,而不是0.1

2.1.3 decimal类型:
精度为128位,浮点变为decimal的时候可能会发生溢出错误,因为decimal比float的范围小。

要显示具有完整精度的数字,必须将子面之显式的声明为decimal类型,要在数字后追加一个m或M,
decimal在范围之内表示的十进制整数都是准确的,但是浮点型则有误差。
2.1.4 string类型:
测试各种拼接:
namespace testDemo
{
classProgram
{
staticvoidMain(string[] args)
{
string a ="hello"+"wlz";
string b ="hello";
b +="wlz";
StringBuilder c =newStringBuilder("hello");
c.Append("wlz");
string d ="hello";
string.Concat(d,"wlz");
Console.Write(a);
}
}
}
IL的代码
.classprivateauto ansi beforefieldinit testDemo.Program
extends[mscorlib]System.Object
{
// Methods
.method private hidebysig static
voidMain(
string[] args
) cil managed
{
// Method begins at RVA 0x2050
// Code size 74 (0x4a)
.maxstack 2
.entrypoint
.locals init (
[0]string a,
[1]string b,
[2]class[mscorlib]System.Text.StringBuilder c,
[3]string d
)
IL_0000: nop
IL_0001: ldstr "hellowlz"
IL_0006: stloc.0
IL_0007: ldstr "hello"
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: ldstr "wlz"
IL_0013: call string[mscorlib]System.String::Concat(string,string)
IL_0018: stloc.1
IL_0019: ldstr "hello"
IL_001e: newobj instance void[mscorlib]System.Text.StringBuilder::.ctor(string)
IL_0023: stloc.2
IL_0024: ldloc.2
IL_0025: ldstr "wlz"
IL_002a: callvirt instance class[mscorlib]System.Text.StringBuilder[mscorlib]System.Text.StringBuilder::Append(string)
IL_002f: pop
IL_0030: ldstr "hello"
IL_0035: stloc.3
IL_0036: ldloc.3
IL_0037: ldstr "wlz"
IL_003c: call string[mscorlib]System.String::Concat(string,string)
IL_0041: pop
IL_0042: ldloc.0
IL_0043: call void[mscorlib]System.Console::Write(string)
IL_0048: nop
IL_0049: ret
}// end of method Program::Main
.method public hidebysig specialname rtspecialname
instance void.ctor () cil managed
{
// Method begins at RVA 0x20a6
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void[mscorlib]System.Object::.ctor()
IL_0006: ret
}// end of method Program::.ctor
}// end of class testDemo.Program
字符串类型的关键在于它是不可变的,可以对其重新赋值,但是不能修改其内容。
2.1.5 null
null只能赋给引用类型,指针类型和可空值类型。和根本不进行赋值相比,将null赋给一个引用类型完全是不同的概念。被赋值为null的变量已被设置,而未进行赋值的变量未被设置,此时在未赋值之前使用该变量,通常会造成一个编译时错误。同样的将null赋给一个string和将""赋给一个string也是不同的。
2.1.6 void
void不是一种数据类型,只是用于指出没有数据类型的这个事实。
2.1.7 var
用于声明隐式类型的局部变量,此时由编译器根据声明内部所赋的值来推断数据类型。
另外要在声明的同时进行赋值,负责会造成编译时错误,添加var的目的是支持匿名类型
例如:
C#代码:
var person =new{ name="wlz",phone="12346"};
IL代码:
[4]class'<>f__AnonymousType0`2'<string,string> person,
IL_004f: ldstr "wlz"
IL_0054: ldstr "12346"
IL_0059: newobj instance voidclass'<>f__AnonymousType0`2'<string,string>::.ctor(!0,!1)
2.2 类型的分类
2.2.1值类型
变量引用的位置就是值在内存中实际存储的位置,因此,将第一个变量的值赋给第二个变量将会在新变量的位置创建原始变量的值的一个内存副本,对第一个变量的值的更改不会影响第二个变量的值,值类型直接包含值。(用栈存储)
2.2.2引用类型
引用类型和引用它们的变量指向数据存储位置,引用类型只是存储一个内存地址,这个地址处才有真正的数据(用堆存储)“运行时”从变量中读取内存位置,然后跳转到包含数据的内存位置。将一个引用类型的变量赋给另一个引用类型的变量,只会多出地址的一个内存副本,此时两个不同的变量也可以引用相同的数据,一个变量对数据进行了修改也会改变另一个变量引用的数据,无论是赋值还是方法调用。
2.3可空修饰符
null值不能赋给一个值类型,但是我们在对数据库操作的时候,经常会碰到一个地方的数字缺失,这时候,我们肯定不能对这个数字赋给其他的值,这样就和数据库中的不一致了,这时我们可以使用可空修饰符?来声明可以存储null的变量。
c#代码:
int? nullNum =null;
int num =42;
IL代码:
[5] valuetype [mscorlib]System.Nullable`1<int32> nullNum,
[6]int32 num
IL_0060: ldloca.s nullNum
IL_0062: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0068: ldc.i4.s 42
IL_006a: stloc.s num
2.4数据类型之间的转换
数据类型之间的转换分为两种,显式转换,隐式转换。
2.4.1显式转换
显式转换带来的后果由你自己承担,比如精度下降,数据丢失,数据未能成功转换时会报错。
int bigNum =int.MaxValue;//2147483647
int result = bigNum +1;
Console.WriteLine(result);//result的值是-2147483648
此处由于溢出使得result被截断了,因而变为了负数
.locals init (
[0]int32 bigNum,
[1]int32 result
)
IL_0000: nop
IL_0001: ldc.i4 2147483647
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.1
IL_0009: add
IL_000a: stloc.1
IL_000b: ldloc.1
关于显式转换这里,C#提供了checked和unchecked关键字,如果加上checked之后上面的代码在编译时会引发一个System.OverflowException(算术运算导致溢出。)
checked
{
int bigNum =int.MaxValue-1;
int result = bigNum +1;
}
此时的IL代码变为下面的样子
.locals init (
[0]int32 bigNum,
[1]int32 result
)
IL_0000: nop
IL_0001: nop
IL_0002: ldc.i4 2147483646
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: add.ovf
IL_000b: stloc.1
IL_000c: ldloc.1
此时由一开始的add变为了add.ovf,add.ovf较add多了一步,就是对两数相加之后执行溢出检查,没有问题才会将其放入栈。
C#中不支持数字变布尔值,0是真1是假,还是相反,不同的地方不同的情况。
2.4.2隐式转换
不会丢失数量级,也不会引发异常的转化即为隐式转换。
2.4.3不进行转型的类型转换
2.4.3.1parse方法
数值数据类型包含该方法
2.4.3.2System.Convert
这是一种类型,以前一直没注意到这一点。
2.4.3.3ToString()方法
2.4.3.4TryParse()方法
C#2.0开始出现,返回值不是对应的转换完成的值,而是是否成功。tryparse不会引发异常,parse则可能会。
C#代码
string text ="9.11E-31";
//Parse
float parseFloat =float.Parse(text);
float tryParseFloat;
//TryParse
bool successParseFloat =float.TryParse(text,out tryParseFloat);
//ToString
string floatToString=tryParseFloat.ToString();
string floatConvertToString=Convert.ToString(parseFloat);
Console.WriteLine(parseFloat);
IL代码
.locals init (
[0]string text,
[1]float32 parseFloat,
[2]float32 tryParseFloat,
[3] bool successParseFloat,
[4]string floatToString,
[5]string floatConvertToString,
[6] bool CS$4$0000
)
IL_0000: nop
IL_0001: nop
IL_0002: ldstr "9.11E-31"
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: call float32[mscorlib]System.Single::Parse(string)
IL_000e: stloc.1//将得到的值出栈(不是入栈)
IL_000f: ldloc.0
IL_0010: ldloca.s tryParseFloat
IL_0012: call bool [mscorlib]System.Single::TryParse(string,float32&)
IL_0017: stloc.3
IL_0018: ldloca.s tryParseFloat
IL_001a: call instance string[mscorlib]System.Single::ToString()
IL_001f: stloc.s floatToString
IL_0021: ldloc.1
IL_0022: call string[mscorlib]System.Convert::ToString(float32)
IL_0027: stloc.s floatConvertToString
IL_0029: ldloc.1
IL_002a: call void[mscorlib]System.Console::WriteLine(float32)
IL_002f: nop
IL_0030: ldloc.3
IL_0031: ldc.i4.0
IL_0032: ceq
IL_0034: stloc.s CS$4$0000
IL_0036: ldloc.s CS$4$0000
IL_0038: brtrue.s IL_0043
2.5数组
一维数组:
数组的声明:
string[] languages;
一维数组声明并赋值:
string[] languages={"C#","Java"};
声明之后再数组赋值:
string[] languages;
languages=newstring[]{"C#","Java"};
C#3.0起,不必在new后面指定数组的数据类型,但是方括号仍是需要的。
声明的同时使用new进行数组赋值:
string[] lanua =newstring[]{"C#","Java"};
在方括号中可以指定数组的大小,但是需要注意,数组的大小和大括号中的元素数量必须匹配。同时也可以分配一个数组但是不指定它的初始值,此时会使用默认值对这些数组元素进行填充。

二维数组:
int[,] table =newint[3,3];
不要丢了new
交错数组:
int[][] crosstable =
{
newint[]{1,0,2},
newint[]{3,2},
newint[]{1},
newint[]{}
};
交错数组不使用逗号来标识一个新的维度,而是定义一个由数组构成的一个数组
访问交错数组:
crosstable[2][2]=1;
要获取一个数组特定的维的长度,不要使用Length属性,而是应该使用GetLength()方法。
bool[,,] cells =new bool[2,3,4];
System.Console.WriteLine(cells.GetLength(2));//获取第三个维度,得到4
System.Console.WriteLine(cells.Length);//24
