Chapter6 方法

Var关键字

Var关键字并不是表示特殊变量。它只是句法上的速记,表示任何可以从初始化语句的右边推断出的类型。
使用Var关键字有一些重要的条件:

  • 只能用于局部变量,不能用于字段;
  • 只能在变量声明中包含初始化时使用;
  • 一旦编辑器推断出变量的类型,它就是固定且不能更改的。

    局部函数

    从C#7.0开始,可以在一个方法中声明另一个单独的方法。这样可以将嵌入的方法跟其他的代码隔离开来,所以它只能在包含它的方法内调用。
    与局部变量必须在使用之前进行声明不同,你可以在包含方法的任意位置声明局部函数。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
                public int TestLocalFunc(int index)
    {
    int LocalFunc(int index)
    {
    return index * index;
    }
    i
    int results = LocalFunc(index);

    return results;
    }
    or
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public int TestLocalFunc(int index)
    {
    int results = LocalFunc(index);

    int LocalFunc(int index)
    {
    return index * index;
    }

    return results;
    }

    ref局部变量

  • 你可以使用这个功能创建一个变量的别名,即使引用的对象是值类型。
  • 对任意一个变量的赋值都会反映到另一个变量上,因为他们引用的是相同的对象,即使是值类型。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
                int x = 1;
    ref int y = ref x;

    Console.WriteLine($"x={x},y={y}");
    x = 666;
    Console.WriteLine($"x={x},y={y}");
    y = 888;
    Console.WriteLine($"x={x},y={y}");
    ---------------------------------------------------------------------------------------------------------------------------------------------
    x=1,y=1
    x=666,y=666
    x=888,y=888

    ref返回

    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
            class Test
    {
    private int Score = 5;

    public ref int RefToValue()
    {
    return ref Score;
    }

    public void Display()
    {
    Console.WriteLine($"Value inside class object:{Score}");
    }
    }
    ---------------------------------------------------------------------------------------------------------------------------------------------
    static void Main(string[] args)
    {
    Test test = new Test();
    test.Display();

    ref int VOutSide = ref test.RefToValue();
    VOutSide = 10;
    test.Display();

    Console.ReadKey();
    }
    ---------------------------------------------------------------------------------------------------------------------------------------------
    Value inside class object:5
    Value inside class object:10

    递归图解

    Chapter7 深入理解类

    静态构造函数

    实例构造函数初始化类的每个新实例,而static构造函数初始化类级别的项。通常,静态构造函数初始化类的静态字段。
    不能从程序中显式调用静态构造函数,系统会自动调用他们。
  • 在类的任何实例被创建之前。
  • 在类的任何静态成员被引用之前。
    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
            class Test
    {
    public Test()
    {
    Console.WriteLine("Normal Construct");
    }

    public static int index = 1;

    static Test()
    {
    Console.WriteLine("Static Construct");
    index = 10;
    }
    }
    ---------------------------------------------------------------------------------------------------------------------------------------------
    static void Main(string[] args)
    {
    Console.WriteLine(Test.index);

    Console.ReadKey();
    }
    ---------------------------------------------------------------------------------------------------------------------------------------------
    Static Construct
    10

    对象初始化语句

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
            class Test
    {
    public int x = 1;
    public int y = 2;
    public Test(int x,int y)
    {
    x = 3;
    y = 4;
    Console.WriteLine("Construct Finish");
    }
    }
    ---------------------------------------------------------------------------------------------------------------------------------------------
    static void Main(string[] args)
    {
    Test test = new Test(7,8){x =5,y=6 };

    Console.WriteLine($"Test x={test.x} y={test.y}");

    Console.ReadKey();
    }
    ---------------------------------------------------------------------------------------------------------------------------------------------
    Construct Finish
    Test x=5 y=6

    索引器

    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
            class Test
    {
    private string oneStr;
    private string twoStr;
    private string threeStr;

    public string this[int index]//索引器声明
    {
    set//set访问器声明
    {
    switch (index)
    {
    case 1:
    oneStr = value;
    break;
    case 2:
    twoStr = value;
    break;
    case 3:
    threeStr = value;
    break;
    }
    }

    get
    {
    switch (index)
    {
    case 1:
    return oneStr;
    case 2:
    return twoStr;
    case 3:
    return threeStr;

    default:
    return "";
    }
    }
    }
    }
    ---------------------------------------------------------------------------------------------------------------------------------------------
    static void Main(string[] args)
    {
    Test test = new Test();
    test[1] = "oneStroneStr";
    test[2] = "twoStrtwoStr";
    test[3] = "threeStrthreeStr";

    Console.WriteLine($"1={test[1]} 2={test[2]} 3={test[3]}");

    Console.ReadKey();
    }
    ---------------------------------------------------------------------------------------------------------------------------------------------
    1=oneStroneStr 2=twoStrtwoStr 3=threeStrthreeStr

Chapter8 使用基类的引用

虚方法和覆写方法

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
class BaseTest
{
public virtual void Print()
{
Console.WriteLine("IM BaseTest");
}
}

class MyTest : BaseTest
{
public override void Print()
{
Console.WriteLine("IM MyTest");
}
}
---------------------------------------------------------------------------------------------------------------------------------------------
static void Main(string[] args)
{
MyTest myTest = new MyTest();
myTest.Print();

BaseTest baseTest = new BaseTest();
baseTest.Print();

BaseTest Back2Base = (BaseTest)myTest;
Back2Base.Print();

Console.ReadKey();
}
---------------------------------------------------------------------------------------------------------------------------------------------
IM MyTest
IM BaseTest
IM MyTest

Chapter10 语句

C#托管对象和非托管对象

托管对象指的是.net可以自动进行回收的资源,主要是指托管对象在堆上分配的内存资源。托管资源的回收工作是不需要人工干预的,有.net运行库在合适的时间进行回收。(手动回收GC.Collect)

非托管对象指.net不知道如何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象,例如文件、窗口、网络连接、数据库连接、画刷、图标等。这类资源,垃圾回收器在清理的时候会调用Object.Finalize()方法。默认情况下,方法是空的,对于非托管对象在此方法中需要编写回收非托管对象的代码,以便垃圾回收器正确回收。(例如我们通常打开文件、图片等后需要进行Close()或者Dispose()去释放)。

本来如果按照上面做法,非托管资源也能够由垃圾回收器进行回收,但是非托管资源一般是有限的,比较宝贵的,而垃圾回收器是由CRL自动调用的,这样就无法保证及时的释放掉非托管资源,因此定义了一个Dispose()方法,让使用者能够手动的释放非托管资源。Dispose()方法释放类的托管资源和非托管资源,使用者手动调用此方法后,垃圾回收器不会对此类实例再次进行回收。Dispose()方法是由使用者调用的,在调用时,类的托管资源和非托管资源肯定都未被回收,所以可以同时回收两种资源。

Microsoft为非托管资源的回收专门定义了一个接口:IDisposable,接口中只包含一个Dispose()方法。任何包含非托管资源的类,都应该继承此接口。

在一个包含非托管资源的类中,关于资源释放的标准做法是:
(1)继承IDisposable()接口;
(2)实现Dispose()方法,在其中释放托管资源和非托管资源,并将对象本身从垃圾回收器中移除(垃圾回收器不在回收此资源);
(3)实现类析构函数,在其中释放非托管资源。
这样做的目的是为了更好的提高程序性能,避免内存泄漏,小数据量往往体现不出来,当数据量庞大时就会出现内存不足以及System.OutOfMemoryException:“Exception_WasThrown”的错误。

Chapter13 数组

int[] 一维数组
int[,] 二维数组
int[][] 交错数组

Chapter15 事件

事件访问器

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
    public class TestEvent
{
public delegate void CustomEvent();

private CustomEvent myEventHandler;

public event CustomEvent MyEventHandler
{
add
{
if (value != null)
{
myEventHandler += value;
myEventHandler += value;
myEventHandler += value;
}
}//执行+=运算符代码
remove
{
if (value != null)
{
myEventHandler -= value;
myEventHandler -= value;
}
}//执行-=运算符代码
}

public void FireAEvent()
{
if (myEventHandler != null)
{
myEventHandler();
}
}
}
---------------------------------------------------------------------------------------------------------------------------------------------
class Program
{
static void Main(string[] args)
{
TestEvent testEvent = new TestEvent();
testEvent.FireAEvent();

testEvent.MyEventHandler += Print;
testEvent.MyEventHandler -= Print;
testEvent.FireAEvent();

Console.ReadKey();
}

static void Print()
{
Console.WriteLine("Invoke Print");
}
}
---------------------------------------------------------------------------------------------------------------------------------------------
Invoke Print

Chapter19 枚举器和迭代器

IEnumerator 枚举器

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
class ColorEnumerator : IEnumerator
{
string[] colors;
int position = -1;

public ColorEnumerator(string[] theColors)//构造函数
{
colors = new string[theColors.Length];
for (int i = 0; i < theColors.Length; i++)
{
colors[i] = theColors[i];
}
}

public object Current//实现Current
{
get
{
if (position == -1 || position >= colors.Length)
{
throw new InvalidOperationException();
}

return colors[position];
}
}

public bool MoveNext()//实现MoveNext
{
if (position < colors.Length - 1)
{
position++;
return true;
}
else
{
return false;
}
}

public void Reset()//实现Reset
{
position = -1;
}
}

IEnumerable 可枚举类型

1
2
3
4
5
6
7
8
9
class Spectrum : IEnumerable
{
string[] Colors = {"violet","blue","cyan","green","yellow","orange","red"};

public IEnumerator GetEnumerator()
{
return new ColorEnumerator(Colors);
}
}

Chapter20 LINQ

查询语法 方法语法

1
2
3
4
5
6
7
8
9
10
11
12
int[] numbers = { 2, 5, 28, 31, 17, 16, 42 };

var numsQuery = from n in numbers//查询语法
where n < 20
select n;

var numsMethod = numbers.Where(N => N < 20);//方法语法


int numsCount = (from n in numbers
where n < 20
select n).Count();//两种形式的组合

Chapter21 异步编程

同步编程与异步编程示例

同步编程

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
    class MyDownloadString
{
Stopwatch sw = new Stopwatch();

public void DoRun()
{
const int LargeNumber = 6_000_000;
sw.Start();
int t1 = CountCharacters(1, "http://www.microsoft.com");
int t2 = CountCharacters(2, "http://www.illustratedcsharp.com");
CountToALargeNumber(1, LargeNumber);
CountToALargeNumber(2, LargeNumber);
}

private int CountCharacters(int id,string urlString)
{
WebClient wc1 = new WebClient();
Console.WriteLine("Starting Call {0} : {1}ms", id, sw.Elapsed.TotalMilliseconds);
string result = wc1.DownloadString(new Uri(urlString));
Console.WriteLine("Call {0} completed : {1}ms", id, sw.Elapsed.TotalMilliseconds);
Console.WriteLine("result length ==> {0}", result.Length);
return result.Length;
}

private void CountToALargeNumber(int id,int value)
{
for (long i = 0; i < value; i++) ;
Console.WriteLine("End counting {0} : {1}ms", id, sw.Elapsed.TotalMilliseconds);
}
}
---------------------------------------------------------------------------------------------------------------------------------------------
class Program
{
static void Main(string[] args)
{
MyDownloadString ds = new MyDownloadString();
ds.DoRun();
}
}
---------------------------------------------------------------------------------------------------------------------------------------------
Starting Call 1 : 20.9274ms
Call 1 completed : 3625.7335ms
result length ==> 180832
Starting Call 2 : 3626.6481ms
Call 2 completed : 4128.4041ms
result length ==> 5164
End counting 1 : 4153.6904ms
End counting 2 : 4177.9644ms

异步编程

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
    class Program
{
static void Main(string[] args)
{
MyDownloadString ds = new MyDownloadString();
ds.DoRun();
}
}
---------------------------------------------------------------------------------------------------------------------------------------------
class MyDownloadString
{
Stopwatch sw = new Stopwatch();

public void DoRun()
{
const int LargeNumber = 6_000_000;
sw.Start();
Task<int> t1 = CountCharactersAsync(1, "http://www.microsoft.com");
Task<int> t2 = CountCharactersAsync(2, "http://www.illustratedcsharp.com");
CountToALargeNumber(1, LargeNumber);
CountToALargeNumber(2, LargeNumber);

Console.WriteLine("Chars in http://www.microsoft.com: {0}",t1.Result);
Console.WriteLine("Chars in http://www.illustratedcsharp.com: {0}", t2.Result);
}

private async Task<int> CountCharactersAsync(int id,string urlString)
{
WebClient wc1 = new WebClient();
Console.WriteLine("Starting Call {0} : {1}ms", id, sw.Elapsed.TotalMilliseconds);
string result = await wc1.DownloadStringTaskAsync(new Uri(urlString));
Console.WriteLine("Call {0} completed : {1}ms", id, sw.Elapsed.TotalMilliseconds);
return result.Length;
}

private void CountToALargeNumber(int id,int value)
{
for (long i = 0; i < value; i++) ;
Console.WriteLine("End counting {0} : {1}ms", id, sw.Elapsed.TotalMilliseconds);
}
}
---------------------------------------------------------------------------------------------------------------------------------------------
Starting Call 1 : 74.7954ms
Starting Call 2 : 771.2391ms
End counting 1 : 791.301ms
End counting 2 : 804.6226ms
Call 1 completed : 1250.2072ms
Chars in http://www.microsoft.com: 180852
Call 2 completed : 1615.1967ms
Chars in http://www.illustratedcsharp.com: 5164