《C#入门经典v6》读书笔记1 C#语言

前言

我说会C#,实际都是皮毛。买了《C#入门经典》(v6)和《C#高级编程》(v9),决定系统地学一遍。这是我的读书笔记而已,不是什么教程,如果有错误,还请各路大神指正。
希望自己坚持看完这两本书,做好笔记,补缺补漏。


第1章 C#简介

Framework 框架
Compact 精简的
OOP(Object-Oriented Programming,面向对象编程)
CTS(Common Type System,通用类型系统)指如int等最基础的数据类型
CLR(Common Language Runtime,公共语言运行库)负责管理用.Net库开发的所有程序的执行
CIL(Common Intermediate Language,通用中间语言)
JIT(Just-In-Time,准时、实时、即时)
GAC(Global Assembly Cache,全局程序集高速缓存)
WPF(Windows Presentation Foundation,Windows呈现基础,取代原来的Windows Form)
WCF(Windows Communication Foundation,Windows通讯平台)
ASP.NET Active Server Pages.NET
ADO.NET Active Data Object.NET
IDE(Integrated Development Environment,集成开发环境)

概念
托管代码 类型安全


第2章 编写C#程序

Console Application 控制台应用程序


第3章 变量和表达式

unsigned 无符号

#region 代码块(可折叠)
#endregion

@逐字指定字符,除双引号外。

基础类型中,string是引用类型,可指定null,其他类型为值类型。

数学运算符 - 取反,+ 不变。

int i = -3;
k = +i;//k=-3
k = -i;//k=3

++运算符放在操作数前面时,操作数在任何其他表达式计算前受到影响,而++运算符放在操作数后面时,操作数在完成表达式计算后才受到++运算符影响。例子见P36。

int i = 3, j = 3,k=0;
k = i++;//k=3
k = ++j;//k=4

为命名空间取别名。

using SL = System.Linq;

第4章 流程控制

逻辑运算符 && || 与 & | 功能一样,但推荐使用前者(性能较高)。

int i = 0;
bool a = (i != 0) && (2 / i > 0);//i为0时,不计算(2 / i > 0)
bool b = (i != 0) & (2 / i > 0);//i为0时,仍计算(2 / i > 0),引发除0错误

goto语句有用但最好不用。

    int i = 5;
    goto lable2;
    i++;//未执行

lable2:
    i--;//i为4

第5章 变量的更多内容

IntelliSense 智能感知
JaggedArray 锯齿数组

char存储的是数值,所以char被当做个数值类型。

checked/unchecked 用于类型转换时,表达式的溢出检查。(不检查时,出现溢出则数据丢失)。

int i = 10000;
byte k = checked((byte)i);

enum 定义枚举,详见P81。

enum Day:short//默认基础类型是int
{
    Monday=1,//默认从0开始
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

数组定义,详见P88。

//一维数组
const int constSize = 5;
int[] array1 = { 1, 2, 3, 4, 5 };//合法,数组默认值{ 1, 2, 3, 4, 5 }
int[] array2 = new int[constSize];//合法,数组默认值为int的默认值0
int[] array3 = new int[constSize] { 1, 2, 3, 4, 5 };//合法,数组默认值{ 1, 2, 3, 4, 5 }

int size = 5;
int[] array4 = new int[size];//合法,数组默认值为int的默认值0
int[] array5 = new int[size] { 1, 2, 3, 4, 5 };//【非法】,此处size应使用常量值(因为已初始化元素)

//矩形数组(每行的元素个数相同)
int[,] array6 = new int[3, 4];//二维数组,3行4列
int[, , ,] array7 = new int[1, 2, 3, 4];//多维数组

//锯齿数组(数组的数组,每行的元素个数可能不同)
int[][] array8 = new int[][]
{                   
    new int[]{1},                  
    new int[]{1,2},
    new int[]{1,2,3}   
};

foreach循环与for循环的主要区别:foreach循环只可只读访问数组元素,而不能修改。

以下标方式访问string的字符时,可读不可写。

string s = "abc";
char c = s[1];//合法,c='b'
s[1] = 'j';//非法,s[1]只读

string.PadLeft() 用于字符串对齐。

string s = "abc",a,b;
a = s.PadLeft(10);//在s左部填充空格以达到长度10
b = s.PadLeft(10,'-');//在s左部填充'-'以达到长度10

第6章 函数

parameter 形式参数(函数定义的一部分)
argument 实际参数(调用代码传递给函数的参数)

参数数组,用params关键字为函数指定一个(只能一个)特殊参数,该参数只能是函数定义的最后一个参数。

static int Sum(params int[] nums)//params参数数组必须是参数定义中的最后一个参数
{
    int sum = 0;
    foreach (int n in nums)
    {
        sum += n;
    }
    return sum;
}
//使用
int sum=Sum(1,2,3,4);//可以指定任意多个int参数

ref参数:用作ref参数(引用参数)的变量有两个限制:已初始化过的非const变量。
out参数:用作out参数(输出参数)的变量可以是未赋值的变量。在函数使用out参数时,应将其看做是尚未赋值的变量。详见P113。

函数签名:函数名+参数。(唯一标志)
函数重载:函数名相同,但函数签名不同。

Main()函数与命令行参数的使用。详见P120。

delegate委托。委托是定义一个函数的类型(指定参数和返回类型),之后可将匹配该类型的函数作为该类型的变量来使用。详见124。

delegate double MyDelegate(int a, int b);//声明委托,指定参数与返回类型
double Multiply(int x, int y) { return x * y; }//与委托匹配的函数1
double Divide(int x, int y) { return x / y; }//与委托匹配的函数2

//使用
MyDelegate d;
double result;

d = new MyDelegate(Multiply);//实例化委托,此时d实际上就是函数Multiply
result = d(1, 2);//  1*2

d = new MyDelegate(Divide);//实例化委托,此时d实际上就是函数Divide
result = d(1, 2);//  1/2

第7章 调试和错误处理

Toggle BreakPoint 插入断点 (Toggle 开关)
SEH(Structured Exception Handling,结构化异常处理)

非中断模式调试:诊断输出(C#功能,Debug.WriteLine()+Trace.WriteLine())+ 跟踪点(VS功能)
中断模式调试:配置断点(断点可以配置几种中断条件)+ Debug.Assert()

Debug.WriteLine() 只能用于调试模式(Debug),将文本写到Output输出窗口。
Trace.WriteLine() 可用于调试+发布模式(Release),将文本写到Output输出窗口。

System.Diagnostics.Debug.WriteLine("a debug message");//仅在调试模式起作用
System.Diagnostics.Trace.WriteLine("a trace message");//在调试+发布模式均起作用

第8章 面向对象编程简介

UML(Unified Modeling Language,统一建模语言)

IDisposable接口与using关键字释放资源。P162。

基类(父类)派生出派生类(子类),派生类继承基类。
seal 密封类,不能用作基类,所以没有派生类。
基类的成员可虚拟(virtual),由派生类重写(override)实现。
abstract 抽象类,不能直接实例化,需被继承。抽象类有抽象成员(需被重写)和非抽象成员(有具体实现)。
interface接口,用于定义通用功能,不可自己实现。

abstract class(抽象类)与interface(接口):
在语法、用法上十分相近,但本质上不同:
抽象类:共性对象(强调属性,是对有相似属性的对象的概括,主要用作对象系列的基类)
接 口:相同功能(强调功能,完全不同的类也可以具有相同的功能)

virtual与abstract:详见P193。
均用于基类中指定成员可被派生类用override关键字重写,区别是:
virtual修饰的方法必须有方法体(实现),abstract修饰的方法不能有方法体(声明);
virtual可以被派生类重写或不重写,abstract必须被重写;
只有抽象类才可使用abstract修饰方法;


第9章 定义类

finalize 完成;结束
DLL(Dynamic Link Library,动态链接库,又称“应用程序拓展”)

class类、interface接口;几种修饰关键字:internal (程序集内部访问)/ public、abstract / sealed

类型比较object.GetType() == typeof(Object)。P181。

无参数构造函数为默认构造函数。

定义的类如果没有使用基类,则只继承于基类System.Object(C#中别名object)。实例化派生类时,基类调用其默认构造函数。因此,实例化一个类时,总是首先调用System.Object.Object()。

值类型与引用类型:值类型(简单类型+结构体struct),引用类型(string+类class),详见P195。

关于对象复制,详见P197+P254。
shallow copy 浅度复制:System.Object的MemberwiseClone(),对引用类型对象复制的是引用。
deep copy 深度复制:实现ICloneable接口的Clone()方法,详见P254。


第10章 定义类成员

refactoring 重构
implementation 实现

readonly关键字:表明字段只能由构造函数或初始化赋值语句进行赋值。

const成员也是静态的,所以不需要static修饰。

字段与属性的区别:

//私有字段,camelCasing
private int number;//字段

//公共字段,PascalCasing
public string Name;//字段

public int Number//属性
{
    get { return number; }

    protected set //可为访问器设置访问性
    {
        //属性控制
        if (value > 0)
        {
            number = value;
        }
        else
        {
            //抛出异常提供控制权
            throw new ArgumentOutOfRangeException("Number", value, "Number 必须大于0");
        }
    }
}

自动属性:由编译器声明对应私有字段

public int Number { get; protected set; }

隐藏基类方法:派生类继承方法前加关键字new。

接口的实现。P217。(隐式、显式实现区别,特殊属性访问器)


第11章 集合、比较和转换

capacity 容量
indexer 索引符
boxing 封箱/装箱
unboxing 拆箱
operator overloading 运算符重载
implicit / explicit 隐式/显式

CollectionBase、DictionaryBase:自定义集合类可继承这两个类,详见P242。

yield关键字:在迭代器块中选择在foreach循环中使用的值。

封箱/装箱:封箱可以看作是浅度复制的过程,值类型封箱引用新副本,引用类型封箱引用源引用类型。

is运算符:用于检查对象是否可以转换为指定类型(基类或接口),可以转换运算符返回true。
classa.GetType()== typeof(ClassA):用于检查对象是否就是指定类型(而不是其派生类等)。

as运算符:用于把一种类型转换为指定的引用类型。以下两句代码等价,但有不同:as运算符进行类型转换失败时返回null,而不抛出异常。详见P279。

return cards.Clone() as Cards;
return (Cards)cards.Clone();

运算符重载:P264

//运算符重载
public static bool operator ==(Card c1, Card c2)
{
    return (c1.suit == c2.suit) && (c1.rank == c2.rank);
}
public static bool operator !=(Card c1, Card c2)
{
    return !(c1==c2);//调用其他运算符减少代码量和错误可能
}

//重写该方法可以确保任何比较技术得到的结果相同
public override bool Equals(object obj)
{
    return this == (Card)obj;//具体比较操作
}
//重写该方法可以确保任何比较技术得到的结果相同
public override int GetHashCode()
{
    return 13 * (int)suit + (int)rank;//根据状态,返回对象实例的唯一int值
}

IComparable接口:在要比较对象的类中实现CompareTo(),比较对象与对象,如:a.CompareTo(b)
IComparer接口:在单独的比较类(比较器)中实现Compare(),如:comparer.Compare(a,b)
arrayList.Sort():使用项的CompareTo()进行默认排序,或传入一个比较器(实现IComparer接口的类)实例进行自定义排序,如arrayList.Sort(comparer)。详见P274。

implicit / explicit 关键字:用于指定隐式/显式类型转换,详见P279。

public static explicit operator ClassA(Class2 obj)
{
    ClassA returnObj = new ClassA();
    checked { returnObj.val = obj.val; }//在显式转换中建议使用checked检查溢出
    return returnObj;
}

第12章 泛型

generic 通用的;一般的
N/A(Not Applicable,不适用(不是Not Available))
predicate 断言;判定

System.Nullable:可空类型,用于使值类型为空null。

//以下两句代码等价
System.Nullable<int> nullableInt1 = null;
int? nullableInt2 = null;

??运算符:可用于为可空类型提供默认值,不需要使用if判断。

op1 ?? op2 //等价于下句
op1 != null ? op1 : op2 //当op1非空时返回op,1,否则返回op2

泛型元素:类、方法、接口、委托,如:

List<T>、Dictionary//泛型类
IComparer<T>、IComparable<T>//泛型接口
Comparison<T>、Predicate<T>//泛型委托
...//泛型方法

default关键字:定义泛型类中根据T是值类型/引用类型赋予值类型默认值/null。
where关键字:约束可用于实例化泛型类的类型。

协变关键字out:协变类型参数只能用作返回值或者属性get访问器(输出)。
抗变关键字in:抗变类型参数只能用作方法参数,不能用作返回类型(输入)。


第13章 其他OOP技术

alias 别名
nest 嵌套;巢
subscribe 订阅

:: 运算符:当命名空间的别名与实际存在的命名空间重名时,编译器默认使用实际命名空间,此时可使用::符号迫使编译器使用由using语句定义的别名。
global关键字:实际是顶级根名称空间的别名。

定制异常:继承基类Exception,用try{…}catch{…}finally{…}捕获。

event关键字:定义事件

//Step0.定义参数类型(必要时),继承EventArgs
public class MyEventArgs : EventArgs
{
    private string message;
    public string Message { get; set; }
    public MyEventArgs(string msg) { message = msg; }
}
//Step1.定义委托,指定事件处理方法的参数和返回类型
//(标准事件委托:void返回类型+object事件源+继承EventArgs的事件参数)
public delegate void MyEventHandler(object sender, MyEventArgs e);
//Step2.定义事件,并指定要使用的委托类型。
public event MyEventHandler LastCardDrawn;

//触发事件
public Card GetCard(int cardNum)
{
//当事件为null时说明该事件没有订阅者,不会引发事件
if (cardNum == 51 && LastCardDrawn != null)
        LastCardDrawn(this, new MyEventArgs("自定义参数"));//触发事件,传递事件参数
    return cards[cardNum];
}

事件处理程序最好使用void返回类型;有返回值时(非void),访问的是最后一个订阅事件的处理程序返回值。

EventHandler、EventHandler:.NET定义的委托类型,使用标准的事件处理模式,其原型为:

public delegate void EventHandler(object sender, EventArgs e);
public delegate void EventHandler(object sender, TEventArgs e);

匿名方法:使用delegate关键字就地定义一个纯粹用作委托目的的处理程序,详见P335。

Attribute特性:对代码进行装饰,如[DebuggerStepThrough],通过反射读取特性值,详见P344。


第14章 C#语言的改进

COM(Component Object Model,组件对象模型)
aggregate 聚合、聚集
accumulate 积累

对象初始化器、集合初始化器:合并实例化与初始化的简化方式。

List farm = new List//集合初始化器
{
    new Chicken(),//调用构造函数进行初始化
    new Cow { Name="Norris" }//对象初始化器:不必显式调用构造函数,直接使用公开属性-值对进行赋值
};

var关键字:进行隐式类型化,依赖于编译器确定变量类型(类型推理)

//用var声明变量时需同时初始化,编译器才能确定变量类型
var myVar = new[] { 1, 2, 3 };//myVar被隐式设置为int[]

匿名类型:只读

var curry = new
{
    Name = "name",
    Age = 5
};

dynamic关键字:动态类型,主要用于处理其他语言创建的对象,尽量避免使用。详见P362。

可选参数:为参数提供默认值,使其成为可选参数。避免使用。(可省去部分函数重载代码)
Optional特性也可定义可选参数,详见P366。

public List<char> GetChar(
    string str,
    bool capitalized = false //可选参数,必须位于参数列表末尾
    )
{
    List<char> chars = new List<char>();
    string newStr = capitalized ? str.ToUpper() : str;
    foreach (char c in newStr)
        chars.Add(c);
    return chars;
}
//使用
List<char> chars = GetChar("string");//等价于
List<char> chars = GetChar("string",false);

命名参数:当一个方法存在多个可选参数时,可使用<形参名>:<形参值>的形式使用指定参数。

List<char> chars = GetChar("string",capitalized : false);

扩展方法:给现有类型添加扩展功能,可提供实用方法库,详见P373。

Lambda表达式(用作委托):只用单一表达式即可完成任务时最佳,否则定义非匿名方法较好

(int a, int b) => a + b//编译器会提取Lambda表达式,创建一个匿名方法
(a, b) => a + b//隐式类型化,由编译器联系上下文确定参数类型,更加灵活
(a, b) => { b++; return a + b; }//含多条代码且返回类型不是void时,需用{}包含代码,用return指定返回值
a => a + b//只有1个隐式类型化参数,可省略括号()
() => Math.PI//没有参数,用空号()表示

Lambda表达式表示为泛型类型:

泛型委托 类型参数 返回类型 举例
Action 0 void 泛型委托Action<> 可表示表达式() => Console.WriteLine("HelloWorld")
Action<> <=8 void 泛型委托Action 可表示表达式(a, b) => Console.WriteLine((a + b).ToString())
Func<> <=9 类型参数中的最后一个 泛型委托Func 可表示表达式(a, b) => a.Length + b.Length (返回值为int)

Lambda表达式和集合,详见P381。
Lambda表达式结合System.Linq的使用见第23章LINQ简介。


(第一部分 C#语言 完)

你可能感兴趣的:(C#)