- 文件——》新建——》项目——》virtual C#——》控制台应用
- UWP:通用(univerals)Windows 平台(Platoform):其创建的应用可以在所有Windows设备上运行。P14
基本语法:
- decimal:比double的精度更高但范围更小
- 字符串插值:
string s = new string($"Hello {world.Text}");?
- 允许对float和double使用%
Console.WriteLine(7.3%2);
- 无穷大:Infinity和NAN:
Console.WriteLine(5/0.0);//Infinity
Console.WriteLine(0/0.0);//NAN
- var:相当于auto
- check和uncheck关键字可以打开/关闭程序中的整数溢出检查
static void Main(string[] args)
{
int i = int.MaxValue;
int j = unchecked(i + 1);
Console.WriteLine(j);
}
- 值类型:
- 引用类型:类是引用类型
A a1=new A(1);
A a2=a1;//a1和a2引用同一对象
A a1=new A(1);
A a2=new A(2);
a2=a1;//为1的实例没有引用,被自动垃圾回收
- null本身为引用类型,用于初始化引用类型,不可用于初始化值类型。表示该变量不引用内存中的任何对象。
- 可空值类型:
可使用null或者值类型初始化,不可赋给值类型变量。
Int? i=null;
If(i.HasValue) i=9;
else Console.WriteLine(i.Value);
ref关键字:类似于C++的引用&
Static void fun(ref int i)
{}out 关键字:必须在函数中初始化该参数
object 关键字:System.Object类的别名。所有的类都是System.Object类的派生类。
装箱:将栈的数据复制到堆上
Int i=2;
object o=i;
- 拆箱:如果类型转换成功,将栈的数据复制到堆上
object o=i;
Int i=(int)o;
注意装箱和拆箱的开销较大,建议使用泛型。
- is操作符:
A a1=new A(1);
object o=a1;
If(o is A){}
- as操作符:
object o=new A(1);
A a1=o as A;//转换失败为null
If(A1!=null){}
- 属性:看起来像字段,用起来像变量
- 可以只包含set或者get访问器
- 可以单独为访问器添加访问符
- 在初始化后使用
- 自动属性P294
- 在接口中指定属性
interface Itest
{
int X{get;set;};
}
class A:Itest
{
//显式实现属性接口是非虚的
int Itest.X
{
get{return this._x;}
set{this._x=fun(value);}
}
}
A a=new A();
int x1=a.X;//调用的是A.get
a.X=3;//调用的是A.set
struct A
{
private _x,_y;//P284
pubilc int X
{
get{return this._x;}
set{this._x=fun(value);}//通过内建的参数传递数据
}
}
- 委托:类似C++泛型算法的谓词
class A
{
delegate void fun();//用delegate关键字声明委托类型
private fun fun1;
pubilc A()
{
this.fun+=t.funf;
this.fun-=t.funf;
//当参数列表不符合时,使用lambda表达式
this.fun+=(()=>s.funs(2));
}
}
- 事件
class A
{
//用delegate关键字声明委托类型
pubilc delegate void fun();
pubilc event fun efun;//登记事件
private void notify()
{
if(this.efun!=null)
{
this.efun();
}
}
}
A a=new A();
a.efun+=t.funf;//订阅事件
- 操作符重载:
- 必须为静态和公共
- 一元操作符没有隐式参数
- 二元操作符必须自行保证顺序无关
- 转换操作符:implicit(隐式转换)和explicit(显式转换)关键字
struct Hour
{
public static Hour operator+(Hour h,int t)
{…}
//通过转换操作符保证顺序无关
public static implicit operator Hour(int t)
{
return new Hour(t);
}
}
- 枚举:P167
- 结构体:值类型
- C#内建的结构P172
- 如果一个概念的重点在于值而非功能,用结构实现。降低管理堆的开销。
- 不可以声明默认构造器,由编译器自动生成。但可以声明非默认的构造器,必须显式初始化所有变量。
- 变量不可在声明时初始化。
- 结构无法继承
struct A
{
private int i;
Public A(int j)
{
i=j;
}
}
A a=new A(1);
A a1=a;//无法自定义赋值操作符
函数:
- 传递具名参数:允许按照不同的顺序传递参数
static void Main(string[] args)
{
void fun(int i,int j=1,int k=2)=> Console.WriteLine(j+k);
fun(j:3,i:2);
}
- 在switch中强制要求为每个case添加break
- 集合初始化列表:比重载更为方便灵活
class A
{
private int i=5;
private int j=5;
public int I
{
set{this.i=value;}
}
public int J
{
set{this.j=value;}
}
}
A a1=new A{i=3};
A a2=new A{i=3,j=6};
类:
- 类的结尾不用分号
- 类的每个成员和函数前面必须添加public和private关键字
- 构造器:就像C++的构造函数
- 分部类:通过partical关键字允许在不同的cs文件中定义1个类的不同部分。
partical class Circle
{…}
- 静态方法:
class Circle
{
public static void fun()
{…}
}
- 1个类只允许从1个类派生,继承总是为公共
Class A:B
{}
- 重写:
Class A
{
public virtual void fun()
{}
}
Class B:A
{
public override void fun()
{}
}
- 在同一继承体系中,任何派生类都可访问受保护的成员
- 抽象类
abstract class A
{
//可以声明抽象方法
public abstract void fun();
}
- 密封:可用于类和函数(最后1个实现)
sealed class A{}//不允许被继承
- 扩展方法:添加静态方法扩展类或者结构
static class Util
{
public static fun(this int i)
//this修饰int,int被扩展
{
return -i;
}
}
- 接口:不包含任何代码,只负责规定从接口继承的类需要实现什么
- 接口扩展:接口A继承接口B
//建议接口以大写字母I开头
interface Itest
{
int fun();//继承时必须全部实现
}
class A:Itest
{
public int fun()//实现必须都为public
{
return 1;
}
}
class A:Itest1,Itest2
{
//由于可以继承多个接口,不同的接口可能会有相同的函数,所以建议显式实现接口
int Itest1.fun()
{
return 1;
}
//由于无法区分不同接口,不能使用访问修饰符
int Itest2.fun()
{
return 2;
}
}
A a=new A();
Itest1 it1=a;
int i=it1.fun();
Itest1 it2=a;
int j=it2.fun();
//允许同时继承类和接口,但是必须先写基类名,后写接口
Class B:A,Itest
{}
- 派生类可以向接口转换
int fun(Itest it)//该函数允许任何实现Itest的类
{}
数组:引用类型
Int[] a;//不用写入数组大小
a=new int[4];//根据数组元素的类型选择相应的默认值(0,null,false)进行初始化
a=new int[4]{9,3,7,2};//数量必须完全匹配
Int[] a={9,3,7,2};
A[] a={new A(1),new A(2)};
Var a=new int[]{9,3,7,2};
- 遍历数组
Foreach(int i in a)
{
Console.WriteLine(i);
}
- 复制数组
Int[] b=new int[a.Lengh];
a.CopyTo(copy,0);
- 多维数组
Int[,] a=new int[4,6];
Int[,,] a=new int[4,6,5];
- 交错数组:每1列的长度都可以不同
Int[][] a=new int[4][];//4列
- 参数数组:比重载更加灵活,用于获取数量可变,类型不同的实参。
Int min(params int[] a)
{}
Int t=min(1,2,3);
Int t=min(1,2);
//注意非params方法优于params方法
Int min(params object[] a)//装箱
{}
集合P3445:容器
索引器:数组的属性
- 每个类或者结构只能定义1个,但是可以重载
- 由于数组为引用类型,建议使用索引器
- 和属性类似,可以在接口中指定,显示实现时为非公和非虚
struct A
{
…
//索引器的方法名为this,后跟方括号
public bool this[int i]
{
set{…}
get{…}
}
}
A a=new A(12);
bool b1=a[2];
a[0]=true;
- 可枚举集合:实现了System.Collections.IEnumerable接口(该接口包含返回枚举器对象的函数GetEnumerator)
- 只有实现该接口才能遍历,为了减少代码重复,C#使用迭代器生成枚举器。
class A<T>:IEnumerable<T>
{
private List<T> data=new List<T>();
IEnumerable<T> IEnumerable<T>.GetEnumerator()
{
foreach(var i in data)
{
yield return i;
}
}
pubilc void fillList(params T [] items)
{
foreach(var i in data)
{
data.Add(i);
}
}
}
- new不可以重载
- C#没有delete,由CLR清理引用对象
- 避免使用析构器
- disposal(资源清理):清理对象所包含的资源,不释放对象的内存
//异常安全:A必须实现IDisposable接口的Dispose函数
using (A a1=new A(1))//不同于引入命名空间的using
{
}
示例:P268
- 静态using语句
这里写代码片
- 泛型:P338-341?
- 异常过滤器P109
- finally块:无论是否抛出异常,在其中的语句都一定会运行(C++资源释放?)
- 数据查询:解耦数据内部结构和查询方式
LINQ:语言集成查询P415
- 重构P59
- 健壮性是指程序在运行过程中出现一般性的错误,程序会自动进行错误处理函数。
可靠性是指程序在运行过程中出现错误的概率
- 语法糖:语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读。不过其并没有给语言添加什么新功能。例如:在C语言里用a[i]表示*(a+i),
1:如果去掉了一个功能,语言有些事情就做不了了,这就不是语法糖,而是基础功能。2:如果去掉了一个功能,语言做那些事情只是麻烦了一点点,这就是语言功能重复,或者只是提供了缩写功能。3:如果去掉了一个功能,语言做那些事情还是能做,但是实在是麻烦太多了,这就是语法糖了。
static void Main(string[] args)
{
void fun()=> Console.WriteLine("yes");
fun();
}
看完书要做题实践
懂得如何取舍,编程能力是一种解决问题的能力。如果问题没能被很好地解决,知道再多也没用。
编程不是解各种脑筋急转弯的问题
计算机科学有两类根本问题。一类是理论:算法,数据结构,复杂度,机器学习,模式识别等。理论走的是深度,是在追问在给定的计算能力约束下如何把一个问题解决得更快更好。
一类是系统:操作系统,网络系统,分布式系统,存储系统,游戏引擎,等等等等。系统走的是广度,是在追问对于一个现实的需求如何在众多的技术中设计出最多快好省的技术组合。
是不提倡“重复发明”,但是提倡“重新制造”。
至少学习半打编程语言。包括一种支持类抽象的语言(例如Java或者C++),一种支持函数抽象的语言(例如Lisp或者ML),一种支持语法抽象的语言(例如Lisp),一种支持声明式编程的语言(例如Prolog或者C++模板),一种支持协同程序的语言(例如Icon或者Scheme),一种支持平行并发编程的语言(例如Sial)