[C#] C#基础入门(一)

本文为C#复习时,知识遗漏处笔记

Csharp编程概述

Chapter_01 关于CLR

程序集

经由编译器编译得到的,供CLR进一步编译执行的那个中间产物,在WINDOWS系统中,它一般表现为·dll或者是·exe的格式,但是要注意,它们跟普通意义上的WIN32可执行程序是完全不同的东西,程序集必须依靠CLR才能顺利执行。



Chapter_02 关于修饰符

C# 方法默认访问级别 : private
C# 类默认访问级别 : internal

命名空间下的元素的默认访问修饰符

public : 同一程序集的其他任何代码或引用该程序集的其他程序集都可以访问该类型或成员。
internal : 同一程序集中的任何代码都可以访问该类型或成员,但其他程序集不可以访问,如果其他程序集中using了该程序集的话,还是可以使用的。

DifferentNameSpace.cs 文件

1
2
3
4
5
6
7
8
9
10
11
using System;
using Properties_Test;
namespace Different {
class Fanwen {
public Fanwen () { }
public void Test () {
Dot dot = new Dot ();
dot.inter_men = 10; //在不同的程序集中访问了本应该访问不了的内容
}
}
}

QualifierT.cs 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using System;
namespace Qualifier_Test {
/// <summary>
/// 关于静态类的测试,如果类没有添加修饰符,类没有修饰符的话就是 internal 
/// </summary>
class Dot {
//类中的内容,如何没有添加修饰的话,默认就是private;其构造函数为public
public int Men1;
int Men2 = 10;

public int pub_men = 12;
/// <summary>
/// 同一程序集中的任何代码都可以访问该类型或成员,但其他程序集不可以访问。 
/// </summary>
internal int inter_men = 13;
/// <summary>
/// 同一类和派生(继承特性)类中的代码可以访问该类型和成员。
/// </summary>
protected int pro_men = 14;
/// <summary>
/// 同一程序集中的任何代码或其他程序集中的任何派生类都可以访问该类型或成员。
/// </summary>
protected internal int pro_inter_men = 15;

#region static + 修饰符 访问测试
/// <summary>
/// 静态成员在堆中单独有一篇空间,就算类没有实例化,依然可以通过类名访问
/// 但是你需要使用public 或者protect interal 等等的修饰符才可以访问到
/// 不然的话,无法访问啊
/// </summary>
static int Men3 = 20;
public static int pub_static_Men = 30;
internal static int inter_static_Men = 31;
protected static int pro_static_Men = 32;
protected internal static int pro_inter_static_Men = 33;
#endregion

public Dot () { }
}
}
不引用命名空间无法在其他命名空间中访问定义好的类 👇



在同一个命名空间中访问非静态成员变量 👇



在同一个命名空间中访问静态成员变量 👇



在其他命名空间中调用不同修饰符的静态成员 👇



在其他命名空间中实例化类并访问不同的成员变量 👇



上面的只是某些情况,下面全面的总结一下

修饰符全家桶

先看看以下的代码,复制到编辑器中
baseclass.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Reivew._7类和继承._01一般的继承
{
class BaseClass
{
int base_defalut_private_member = 10;
static int base_defalut_member = 10;
private int base_private_member = 10;
internal int base_internal_member = 10;
protected int base_protected_member = 10;
protected internal int base_protected_internal_member = 10;
public int base_public_member = 10;


#region static member
static int base_defalut_static_member = 10;
private static int base_private_static_member = 10;
internal static int base_internal_static_member = 10;
protected static int base_protected_static_member = 10;
protected internal static int base_protected_internal_static_member = 10;
public static int base_public_static_member = 10;
#endregion

#region function
void base_defalut_function() { Console.WriteLine("base_defalut_function"); }
private void base_private_function() { Console.WriteLine("base_private_function"); }
internal void base_internal_function() { Console.WriteLine("base_internal_function"); }
protected void base_protected_function() { Console.WriteLine("base_protected_function"); }
protected internal void base_protected_internal_function() { Console.WriteLine("base_protected_internal_function"); }
public void base_public_function() { Console.WriteLine("base_public_function"); }

/// <summary>
/// 虚函数和抽象函数不能使用private修饰
/// </summary>
protected virtual void base_default_virtual_function() { Console.WriteLine("我是父类的虚函数!"); }
#endregion

#region static function
static void base_defalut_static_function() { Console.WriteLine("base_defalut_static_function"); }
private static void base_private_static_function() { Console.WriteLine("base_private_static_function"); }
internal static void base_internal_static_function() { Console.WriteLine("base_internal_static_function"); }
protected static void base_protected_static_function() { Console.WriteLine("base_protected_static_function"); }
protected internal static void base_protected_internal_static_function() { Console.WriteLine("base_protected_internal_static_function"); }
public static void base_public_static_function() { Console.WriteLine("base_public_static_function"); }
#endregion
}
}

subclass.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using System;

namespace Reivew._7类和继承._01一般的继承
{
/// <summary>
/// 子类
/// 类默认的修饰符为internal
/// </summary>
class SubClass : BaseClass
{
int member = 1;
/// <summary>
/// 子类独有的函数
/// </summary>
void SubClassownFunction()
{
Console.WriteLine("子类独有的函数!");
}

/// <summary>
/// 看看子类中,使用不同的对象能够访问那些方法
/// </summary>
void SubFunctoBase()
{
BaseClass bc = new BaseClass();
bc.base_internal_function();
bc.base_protected_internal_function();
bc.base_public_function();

BaseClass bc_subc = new SubClass();
bc_subc.base_internal_function();
bc_subc.base_protected_internal_function();
bc_subc.base_public_function();

//SubClass sub_c = new BaseClass();//使用父类不能实例化子类对象,违反了里斯转换原则
SubClass sub_c = new SubClass();
sub_c.base_default_virtual_function();
sub_c.base_internal_function();
sub_c.base_protected_function();
sub_c.base_protected_internal_function();
sub_c.base_public_function();
sub_c.SubClassownFunction();

BaseClass.base_internal_static_function();
BaseClass.base_protected_internal_static_function();
BaseClass.base_protected_static_function();
BaseClass.base_public_static_function();
}

/// <summary>
/// 使用new关键字覆盖掉父类的函数
/// </summary>
public new void base_public_function()
{
Console.WriteLine("哈哈,现在父类的这个函数已经被我统治了!");
}

protected override void base_default_virtual_function()
{
//base.base_default_virtual_function();
Console.WriteLine("子类重写父类的函数");
}
}
}

test.cs 相同程序集的没有继承关系的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System; 

namespace Reivew._7类和继承._01一般的继承
{
class Inheirt_mine
{
void Func_test()
{
BaseClass bc = new BaseClass();
bc.base_internal_member = 10;
bc.base_protected_internal_member = 10;
bc.base_protected_internal_function();

SubClass sc = new SubClass();
sc.base_internal_function();
sc.base_protected_internal_function();
sc.base_public_function();
}
}
}

ClassT.cs 不同程序集中的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using Reivew._7类和继承._01一般的继承;

namespace Reivew
{
class ClassT
{
public void T()
{
BaseClass bc = new BaseClass();
bc.base_protected_internal_function();
bc.base_public_function();
bc.base_internal_function();

SubClass sc = new SubClass();
sc.base_internal_function();
sc.base_protected_internal_function();
sc.base_public_function();

BaseClass.base_internal_static_function();
BaseClass.base_protected_internal_static_function();
BaseClass.base_public_static_function();
}
}
}

结论__在不同的内容中访问父类中的不同修饰符的方法

修饰符 父类中(直接在某一个函数内部访问) 子类中(在子类中访问父类方法) 其他同程序集的类(使用父类访问) 不同程序集的类
private yes no no no
protected yes yes no no
internal yes yes yes yes
protected internal yes yes yes yes
public yes yes yes yes
static private yes no no no
static protected yes yes no no
static internal yes yes yes yes
static protected internal yes yes yes yes
static public yes yes yes yes

在其他程序集中的类不能直接访问到该程序集中为internal的类 (类只能声明成为internal或者是public的) – 使用using [程序集]即可访问
成员不能比类的访问级别更高;


各类型中的成员的默认访问修饰符

1
2
3
4
5
剩下的修饰符主要是正对继承这个语言特性的,拥有继承的类型有两个类(class)和接口(interface)。
public,internal同样可以用于类型成员。
private : 同一类和结构的代码可以访问该类型和成员。
protected : 同一类和派生(继承特性)类中的代码可以访问该类型和成员。
protected internal :  同一程序集中的任何代码或其他程序集中的任何派生类都可以访问该类型或成员。

MSDN提示

1
2
3
4
1.) 派生类的可访问性不能高于其基类型。换句话说,不能有从内部类 A 派生的公共类 B。
如果允许这种情况,将会使 A 成为公共类,因为 A 的所有受保护的成员或内部成员都可以从派生类访问。 
2.) 成员的可访问性决不能高于其包含类型的可访问性。 
3.) 可以使用五种访问类型中的任何一种来声明类成员(包括嵌套的类和结构)。

接口(interface)

1
2
3
接口成员访问修饰符默认为public,且不能显示使用访问修饰符。
接口成员的访问级别是默认的(默认为public),所以在声明时不能再为接口成员指定任何访问修饰符,否则 编译器会报错。
接口成员不能有static、abstract、override、virtual修饰符,使用new修饰符不会报错,但会给出警告说不需要关键字new。

类(class)

1
2
3
构造函数 默认为public访问修饰符。
析构函数 不能显示使用访问修饰符且默认为private访问修饰符。 
类的成员 默认访问修饰符为private;

枚举(enum)

1
枚举类型成员默认为public访问修饰符,且不能显示使用修饰符。

结构(struct)

1
2
结构成员默认为private修饰符。 
结构成员无法声明为protected成员,因为结构不支持继承。

嵌套类型

1
嵌套类型的默认访问修饰符为private。 和类,结构的成员默认访问类型一致。

andrew_wx



Chapter_03 深入理解类

修饰符的顺序

1
2
3
4
5
6
7
[特性] [修饰符] 核心声明
+ 修饰符
- 放在核心声明前
- 多个修饰符,任意顺序
+ 特性
- 放在修饰符,核心声明之前
- 多个特性,任意位置

静态字段

类的静态在类的声明之时就分配了内存,堆中的内存;
不用使用实例化的对象就可以直接访问;

1
2
3
4
5
6
7
8
9
10
11
12
class C{
public static int Mem1;
public static void Func(int M){
Console.WriteLine("C" + M);
}
}

class Program{
public static void Main(){
C.Func(c.Mem1);
}
}

数据成员-储存数据 函数成员执行代码
+字段 +方法
+类型 +属性
常量 +构造函数
+运算符
+事件
索引器
带上了+的可为static


Chapter_04 类和继承

静态构造函数

静态构造函数初始化类的静态字段

1
2
3
4
5
6
7
8
9
10
+ 初始化类级别的项
- 在引用任何静态成员zhiqian
- 在创建类的任何实例之前
+ 和实例构造函数的相似之处
- 不能有返回值
- 函数名和类名相同
+ 和实力构造函数的不同之处
- 使用static
- 只能有一个,还不能带上参数
- 不能有访问修饰符

构造函数的执行

构造函数的初始化顺序

先看一个例子

1
2
3
4
5
6
7
8
9
10
11
12
using System; 

namespace Reivew._7类和继承._02构造函数的执行顺序
{
class BaseC
{
public BaseC()
{
Console.WriteLine("爸类的构造函数 -- 我是一代爸爸");
}
}
}

1
2
3
4
5
6
7
8
9
10
namespace Reivew._7类和继承._02构造函数的执行顺序
{
class SubC: BaseC
{
public SubC()
{
Console.WriteLine("子类的构造函数 -- 我是儿砸");
}
}
}
1
2
3
4
5
6
7
8
9
10
namespace Reivew._7类和继承._02构造函数的执行顺序
{
class SubSubC: SubC
{
public SubSubC()
{
Console.WriteLine("子子类的构造函数 -- 我是儿砸的儿砸");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;
using Reivew._7类和继承._02构造函数的执行顺序;
namespace Reivew
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("爸爸出没!");
BaseC bc = new BaseC();
Console.WriteLine("_+-=-=-=-=-=-=-=-=+++_=-==-");
Console.WriteLine("儿砸出没!");
SubC sc = new SubC();
Console.WriteLine("_+-=-=-=-=-=-=-=-=+++_=-==-");
Console.WriteLine("儿砸的儿砸出没!");
SubSubC ssc = new SubSubC();
Console.WriteLine("_+-=-=-=-=-=-=-=-=+++_=-==-");
Console.WriteLine("_+-=-=-=-=-=-=-=-=+++_=-==-");
Console.WriteLine("使用儿砸实例化爸爸");
BaseC bsc = new SubC();
Console.WriteLine("_+-=-=-=-=-=-=-=-=+++_=-==-");
Console.WriteLine("使用孙子实例化儿砸");
SubC sssc = new SubSubC();
Console.WriteLine("_+-=-=-=-=-=-=-=-=+++_=-==-");
Console.WriteLine("使用孙子实例化爸爸");
BaseC bssc = new SubSubC();
Console.ReadKey();
}
}
}

被调用的子类成员初始化 -> 调用父类构造函数 -> 调用子类的构造函数 -> 调用子类的子类的构造函数 -> …

FBIWARNING 推荐在构造函数中调用虚方法,因为调用基类的构造函数时,初始化虚方法需要调用派生类中的覆写方法;但是在执行派生类的构造函数之前,固使用调用会在派生类没有初始化前传递到派生类


构造函数的初始化语句

因为父类中可能不止一个默认的构造函数,毕竟构造函数也是可以重载的嘛
当派生类继承了父类的时候,当其初始化的时候,调用父类的构造函数的时候,就可能会出现混乱
所以我们有了以下的两种解决方法

方式一 使用base

显示的调用父类的构造函数,使用父类的构造函数初始化子类的构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;

namespace Reivew._7类和继承._03显示调用父类的构造函数
{
class Base03
{
public int num = 0;
public int tun = 0;

public Base03()
{
Console.WriteLine("父类基本构造函数{0} {1}", num, tun);
}

/// <summary>
/// 使用了父类的一个构造函数初始化该构造函数
/// </summary>
/// <param name="num"></param>
/// <param name="tun"></param>
public Base03(int num, int tun)
{

Console.WriteLine("父类重载构造函数{0} {1}", num, tun);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
namespace Reivew._7类和继承._03显示调用父类的构造函数
{
class Sub03 : Base03
{
public int sun = 10;
/// <summary>
/// 默认调用了base03(int,int)这个构造函数
/// </summary>
/// <param name="suns"></param>
public Sub03() : base(0, 10)
{
Console.WriteLine("子类重载构造函数");

}

public void AccessB()
{
Console.WriteLine("{0},{1},{2}", num, tun, sun);
}
}
}

方式二 使用this

一个类中有多个构造函数的时候,使用已经存在的一个构造函数初始化其他的构造函数;
提一种情况 👇
一个类中有好几个构造函数,他们需要在对象构造的过程开始时执行一些公共的代码;我们这个时候就可以将这部分公共的代码放在一个构造函数中,用来初始化其他的构造函数,减少重复的代码
其他不算好的方法👇
将公有的代码放在一个函数中间,然后使用构造函数调用这个方法?
第一,要知道,编译器对构造函数有优化; 第二,像有些代码只能通过构造函数初始化,像readonly关键字修饰的字段,就只能在构造函数中初始化;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
namespace Reivew._7类和继承._03显示调用父类的构造函数
{
class Base03
{
public int num = 0;
public int tun = 0;

public Base03()
{
Console.WriteLine("父类基本构造函数{0} {1}", num, tun);
}

public Base03(int x,string s):this(5)
{
Console.WriteLine("父类构造函数02" + x + s);
}

/// <summary>
/// 使用了父类的一个构造函数初始化该构造函数
/// </summary>
/// <param name="num"></param>
/// <param name="tun"></param>
public Base03(int num, int tun):this(5)
{

Console.WriteLine("父类重载构造函数{0} {1}", num, tun);
}

public Base03(int x)
{
num = x;
tun = x;
Console.WriteLine("父类重载构造函数One{0} {1}", num, tun);
}
}
}

调用

1
Base03 bs = new Base03(1,2);

这里插一句 - 类中的属性中的访问器要比该属性的访问性低 public > protected internal > protected = internal > private; (类的修饰符只有internal和public两种)类中成员的修饰符等级也是比类的修饰符等级低的;


程序集间的继承

不同程序集中定义基类派生类,是有条件的

1
2
+ 基类必须声明为public (外部程序集才能访问它)
+ 必须在vs工程中reference节点中添加包含该基类的程序集的引用;

成员修饰符的可访问性






成员访问性总结👇


抽象成员

抽象成员指的是设计为被覆写的函数成员,和virtual成员对比如下

抽象类

抽象类的注意要点

1
2
3
4
5
6
7
+ 不能创建实例;
+ 使用abstract修饰;
+ 只有抽象类中才能出现抽象成员;
+ 抽象类中可以存在非抽象的成员;
+ 可以从该抽象类中派生出新的抽象类;
+ 只有方法,属性,事件,索引器可以被声明为抽象成员;
+ 派生自抽象类的类必须使用override实现该类的所有的抽象成员;除非派生类也是抽象类;

抽象类的应用场景

详细内容见

1
2
3
4
5
6
7
8
+ 定义了一组接口,但又不想强迫每个实现类都必须实现所有的接口。
可以用abstract class定义一组方法体,甚至可以是空方法体,然后由子类选择自己所感兴趣的方法来覆盖。

+ 某些场合下,只靠纯粹的接口不能满足类与类之间的协调,还必需类中表示状态的变量来区别不同的关系。
abstract的中介作用可以很好地满足这一点。

+ 规范了一组相互协调的方法,其中一些方法是共同的,与状态无关的,可以共享的,无需子类分别实现;
而另一些方法却需要各个子类根据自己特定的状态来实现特定的功能

abstract和virtual的比较

比较

1
2
3
4
5
6
7
抽象方法是需要子类去实现的.
虚方法,是已经实现了,子类可以去覆盖,也可以不覆盖取决于需求.

虚方法和抽象方法都可以供派生类重写,它们之间有什么区别呢?
1. 虚方法必须有实现部分,抽象方法没有提供实现部分,抽象方法是一种强制派生类覆盖的方法,否则派生类将不能被实例化。
2. 抽象方法只能在抽象类中声明,虚方法不是。其实如果类包含抽象方法,那么该类也是抽象的,也必须声明为抽象的。
3. 抽象方法必须在派生类中重写,这一点跟接口类似,虚方法不必。

密封类

1
2
+ 不能作为基类;
+ 使用sealed关键字;

静态类

用于存放不受实例数据影响的数据和函数
一个常见的用法 – 创建包含一组数学方法和值的数学库;

1
2
3
4
+ 所有的成员都是静态的
+ 使用static
+ 可以有一个静态构造函数,不能创建该类的实例(不可以 staticType s = new staticType();) -> 初始化静态类中的静态字段
+ 静态类不可被继承(隐式密封的)

拓展方法

1
2
3
+ 必须是静态类
+ 方法本身也是static的
+ 方法必须包含关键字this作为器第一个参数类型,并在后面跟着他所拓展的类的名称;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 namespace ExtensionMethods {
sealed class MyData
{
private double D1, D2, D3;
public MyData(double d1, double d2, double d3) { D1 = d1; D2 = d2; D3 = d3; }
public double Sum() { return D1 + D2 + D3; }
}
static class ExtendMyData
{ //就是这个👇
public static double Average(this MyData md)
{
return md.Sum() / 3;
}
}
class Program
{
static void Main()
{
MyData md = new MyData(3, 4, 5);
Console.WriteLine("Sum: {0}", md.Sum());
Console.WriteLine("Average: {0}", md.Average());
}
}
}
1
2
3
输出
Sum: 12
Average: 4


Chapter_05 表达式和运算符

字面量

整数,实数,字符,字符串字面量;
强调一下字符串字面量: 逐字字面量使用一个@为前缀;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+ 逐字字面量转义字符串不会被求值
+ 相邻双引号解释成为单个双引号

string rst1 = "Hi there!";
string vst1 = @"Hi there!";
string rst2 = "It started, \"Four score and seven...\"";
string vst2 = @"It started, ""Four score and seven...""";
string rst3 = "Value 1 \t 5, Val2 \t 10"; // Interprets tab esc sequence
string vst3 = @"Value 1 \t 5, Val2 \t 10"; // Does not interpret tab
string rst4 = "C:\\Program Files\\Microsoft\\";
string vst4 = @"C:\Program Files\Microsoft\";
string rst5 = " Print \x000A Multiple \u000A Lines";
string vst5 = @" Print
Multiple
Lines";

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Hi there! Hi there! 

It started, "Four score and seven..."
It started, "Four score and seven..."

Value 1 5, Val2 10
Value 1 \t 5, Val2 \t 10

C:\Program Files\Microsoft\
C:\Program Files\Microsoft\

Print
Multiple
Lines

Print
Multiple
Line

注意

编译器让相同的字符串字面量共享堆中的同一个内存位置 以节省内存

string是值类型还是引用类型
String是引用类型,只是编译器对其做了特殊处理。

C#中 数字不具有布尔意义

条件逻辑运算符

&& 与 两个操作数为true,结果为true; 其他为false
|| 或 如果至少一个操作是true,结果为true; 否则为false;
! 非 如果操作数是false,结果为true; 否则为false;

逻辑运算符

用户自定义类型转换

有点类似重载某一个运算符或者关键字
声明用户隐式转换语法

1
2
3
4
5
  👇  必须👇要      
public static implicit operator 目标类型(源数据 identifier){
...
return ObjectofTargetType;
}

声明用户显式转换语法

1
2
3
4
5
  👇  必须👇要      
public static explicit operator 目标类型(源数据 identifier){
...
return ObjectofTargetType;
}

举一个例子 – 隐式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class LimitedInt
{
int _value;
public int Value {
get => _value;
set => _value = value;
}
public static implicit operator int(LimitedInt li)
{
return li.Value;
}
public static implicit operator LimitedInt(int i)
{
LimitedInt li = new LimitedInt();
li.Value = i;
return li;
}
}


调用↓
class Program{
static void Main(string[] args){
LimitedInt li =(LimitedInt)500;
int value = (int)li;
}
}

举一个例子 – 显式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class LimitedInt
{
int _value;
public int Value {
get => _value;
set => _value = value;
}
public static explicit operator int(LimitedInt li)
{
return li.Value;
}
public static implicit operator LimitedInt(int i)
{
LimitedInt li = new LimitedInt();
li.Value = i;
return li;
}
}


调用↓
class Program{
static void Main(string[] args){
LimitedInt li =500;
int value = li;
}
}

运算符重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 class LimitedInt
{
private int _theValue = 0;
public int TheValue
{
get
{
return _theValue;
}
set
{
if (value < MinValue) _theValue = 0;
else _theValue = value > MaxValue ? MaxValue : value;
}
}
const int MaxValue = 100; const int MinValue = 0; public static LimitedInt operator -(LimitedInt x)
{ // In this strange class, negating a value just sets its value to 0.
LimitedInt li = new LimitedInt(); li.TheValue = 0; return li;
}
public static LimitedInt operator -(LimitedInt x, LimitedInt y)
{
LimitedInt li = new LimitedInt(); li.TheValue = x.TheValue - y.TheValue; return li;
}
public static LimitedInt operator +(LimitedInt x, double y)
{
LimitedInt li = new LimitedInt(); li.TheValue = x.TheValue + (int)y; return li;
}
}

class Program
{
static void Main()
{
LimitedInt li1 = new LimitedInt();
LimitedInt li2 = new LimitedInt();
LimitedInt li3 = new LimitedInt();
li1.TheValue = 10;
li2.TheValue = 26;
Console.WriteLine(" li1: {0}, li2: {1}", li1.TheValue, li2.TheValue);
li3 = -li1;
Console.WriteLine("-{0} = {1}", li1.TheValue, li3.TheValue);
li3 = li2 - li1;
Console.WriteLine(" {0} - {1} = {2}", li2.TheValue, li1.TheValue, li3.TheValue);
li3 = li1 - li2;
Console.WriteLine(" {0} - {1} = {2}", li1.TheValue, li2.TheValue, li3.TheValue);
}
}


Chapter_06 语句,结构和枚举

只统计自己不是太清楚的内容

跳转语句

1
2
3
4
5
break;
continue;
goto;
return;
throw;

using 语句

某一些类型的非托管对象有数量限制 or 非常消耗系统的资源;在代码使用完他们之后,应该尽快的将其释放掉;using语句能够简单的处理该过程并且保证他们都有一个比较好的归宿(doge);

资源–>一个实现了System.IDisposable接口的类或者结构;

使用资源有以下的几个阶段:

1
2
3
+ 分配资源
+ 使用资源 - 如果在使用资源的过程中出发了异常,处置资源的过程可能就执行不了了;
+ 处置资源

using 语句的使用方式

方式一:

1
2
3
4
5
6
7
8
9
        // 分配资源👇
using(资源类型 source = 表达式){
执行代码; //👈使用资源
}


+ 分配资源
+ 将执行代码放在try块中
+ 创建资源的Dispose方法的调用,并将其放进finally块中;

方式二:

1
2
3
4
5
6
using (资源) 使用资源


TextWriter tw = File.CreateText("Lincoln.txt"); // Resource declared
using ( tw ) // using statement
tw.WriteLine("Four score and seven years ago, ...");

~

using 语句的一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.IO;
namespace Reivew
{
class Program
{
static void Main(string[] args)
{
using (TextWriter tw = File.CreateText("Lincoln.txt"))
{
tw.WriteLine("Four score and seven years ago, ...");
}

using (TextReader tr = File.OpenText("Lincoln.txt"))
{
string InputString;
while (null != (InputString = tr.ReadLine())) Console.WriteLine(InputString);
}
Console.ReadKey();
}
}
}

结构 – 值类型

和C++中的结构体相仿(或者是相同的东西)

结构的 构造函数(有的) 析构函数(别想了)

可以有实例构造函数和静态构造函数;没有析构函数(毕竟时值类型嘛)

1
2
每一个结构中都存在默认的构造函数,要想重载构造函数的话 -- 带上参数吧
要调用构造函数的话,即使没有在堆中分配对象,也要使用new关键字;

其静态构造函数作用同类的静态构造函数
在以下场景会被使用到(且发生在下面的情况之前)

1
2
+ 调用显示声明的构造函数
+ 引用结构的静态成员

注意内容

1
2
3
4
5
+ 不可以对结构中的字段初始化
+ 结构是sealed
+ 结构是值类型
+ *预定义的简单类型(int short ..)其实在.net中实现为结构
+ *可以使用实现分布类的方式 实现 分部结构

枚举 – 值类型

枚举只有命名的整数值常量;

1
enum TrafficLight { Green, Yellow, Red }

空间位置

PS:深入了解见Blog中的其他文章



Chapter_07 数组

重要的细节

C#中的数组

1
2
+ 数组一旦被创建了,大小就固定了;(不支持动态数组)
+ 从0开始


数组的类型

1
2
3
4
5
6
+ 一维数组
+ 多维数组
+ 矩形数组
int x = Array[4,5,6];
+ 交错数组
jagArray[2][7][4];

传说中的二维数组为int[,] two = new int[3,3];


矩形数组的初始化

1
2
3
int[,] two = new int[2, 3] { { 1, 2, 3 }, { 2, 3, 4 } };
等价于
int[,] two = { { 1, 2, 3 }, { 2, 3, 4 } };


交错数组的初始化

1
2
int[][] jagArr = new int[3][];   //√
int[][] jagArr2 = new int[3][4]; //× -- 编译错误


交错数组的实例化

1
2
3
4
int[][] Arr = new int[3][];                  // 1. Instantiate top level.        
Arr[0] = new int[] {10, 20, 30}; // 2. Instantiate subarray.
Arr[1] = new int[] {40, 50, 60, 70}; // 3. Instantiate subarray.
Arr[2] = new int[] {80, 90, 100, 110, 120}; // 4. Instantiate subarray.


交错数组和矩形数组的比较


数组的迭代

使用foreach遍历矩形数组

1
2
3
4
5
6
7
8
9
10
11
12
class Program
{
static void Main(string[] args)
{
int total = 0;
int[,] arr1 = { { 10, 11 }, { 12, 13 } };
foreach (var element in arr1) {
total += element;
Console.WriteLine("Element: {0}, Current Total: {1}", element, total);
}
}
}

使用foreach遍历交错数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Program
{
static void Main()
{
int total = 0;
int[][] arr1 = new int[2][];
arr1[0] = new int[] { 10, 11 };
arr1[1] = new int[] { 12, 13, 14 };
// Process the top level.
foreach (int[] array in arr1)
{
Console.WriteLine("Starting new array");
// Process the second level.
foreach (int item in array)
{
total += item;
Console.WriteLine(" Item: {0}, Current Total: {1}", item, total);
}
}
}
}


数组的协变

即使对象不是数组的基类型,我们也可以将其赋值给数组元素;这种性质就叫做数组的协变;

1
2
+ 数组是引用类型的数组;
+ 在赋值对象的类型和数组基类型之间有隐式类型转换或者显示转换;

举一个例子


数组中的常用的内容

Clone方法

clone是浅复制;他只创建了数组本身的克隆;

1
2
+ 值类型数组 的 clone   :  产生两个独立的数组;
+ 引用类型数组 的 clone : 产生指向相同对象的两个数组;

1
2
3
4
5
6
7
8
clone 值类型
static void Main() {
int[] intArr1 = { 1, 2, 3 }; // Step 1
int[] intArr2 = (int[]) intArr1.Clone(); // Step 2
intArr2[0] = 100;
intArr2[1] = 200;
intArr2[2] = 300; // Step 3
}

1
2
3
4
5
6
7
8
9
10
11
12
13
clone 引用类型
class A { public int Value = 5; }

class Program {
static void Main () {
A[] AArray1 = new A[3] { new A (), new A (), new A () }; // Step 1
A[] AArray2 = (A[]) AArray1.Clone(); // Step 2

AArray2[0].Value = 100;
AArray2[1].Value = 200;
AArray2[2].Value = 300; // Step 3
}
}


C#基础入门(一) 完