1.类部分类/继承/多态/抽象类
部分类partical修饰就可以了,CRL会合并多个文件中的部分类,静态类是只包含静态成员的类不能实例化,用.访问。
类继承分为:继承和接口继承
类是单继承,多接口继承。
结构体不可以继承,可以多继承接口。
虚函数基类virtual声明,子类override声明。
纯虚函数,纯虚基类,也就是抽象类和抽象方法,要用abstract来声明,不能实现abstract方法,可以有数据成员和函数成员,abstract方法之类也要override声明。
非虚函数重写要用new修饰,子类调用基类可以通过base调用。
不可继承不可重写的类或方法用sealed来修饰,如果要重写sealed总是和override一起使用。
类是单继承,多接口继承。
结构体不可以继承,可以多继承接口。
虚函数基类virtual声明,子类override声明。
纯虚函数,纯虚基类,也就是抽象类和抽象方法,要用abstract来声明,不能实现abstract方法,可以有数据成员和函数成员,abstract方法之类也要override声明。
非虚函数重写要用new修饰,子类调用基类可以通过base调用。
不可继承不可重写的类或方法用sealed来修饰,如果要重写sealed总是和override一起使用。
2.类和方法的访问修饰符
方法还有一些修饰符,new是用来重写的,sealed类不能继续,sealed成员重写只能和override一起。
类
成员readonly比static/const更加灵活
,可以构造函数中初始化一次且每个类可以有不同的值,不必用私有的公有的外部也不能修改。
类数据成员有:字段,常量,事件。函数成员有:方法,属性,构造终结器,索引器,方法都是有访问修饰符的。
3.类的构造函数和析构函数
类构造函数,声明了不管有无参数都不会再提供了,base/this引用。
类构造函数,每个类负责自己的私有成员,初始化顺序是从上到下,权限是每个类才能访问到自己的私有成员,生成规则是默认提供但是一旦声明有参数或无参数后就不能生成默认的构造函数,如果是父亲类则子类需要用base显式调用。
提供了构造函数,那么默认构造还是不调用,值又是多少还是默认的值不用担心,结构体或类声明一个自己的构造函数没有初始化完所有的数据编译器也会给默认的初始值,好习惯是要全部初始化下( cpp Style )。
静态构造函数CRL调用; 函数初始化器base 基类构造函数 ,this当前类可以代表最接近的构造函数。
类构造函数,每个类负责自己的私有成员,初始化顺序是从上到下,权限是每个类才能访问到自己的私有成员,生成规则是默认提供但是一旦声明有参数或无参数后就不能生成默认的构造函数,如果是父亲类则子类需要用base显式调用。
提供了构造函数,那么默认构造还是不调用,值又是多少还是默认的值不用担心,结构体或类声明一个自己的构造函数没有初始化完所有的数据编译器也会给默认的初始值,好习惯是要全部初始化下( cpp Style )。
静态构造函数CRL调用; 函数初始化器base 基类构造函数 ,this当前类可以代表最接近的构造函数。
object类方法finaliaze通过手动释放可以提高效率,gettype可以返回类的很多信息,是反射技术入口,只是浅拷贝引用。
4.接口
抽象类也不能实例化,抽像方法不能直接实现,但可以包含非抽象的成员和数据成员。
接口类和抽象类的差别,抽象类可以有实现方法和数据成员,单抽象函数不能实现;也就是接口更加抽象定义协定。
using System;
// 命名空间后面声明,但前面using就可以让下面的模块相互调用了
using Wrox.ProCSharp;
using Wrox.ProCSharp.VenusBank;
using Wrox.ProCSharp.JupiterBank;
namespace Wrox.ProCSharp
{
class MainEntryPoint
{
static void Main()
{
IBankAccount venusAccount = new SaverAccount();
ITransferBankAccount jupiterAccount = new CurrentAccount();
venusAccount.PayIn(200);
jupiterAccount.PayIn(500);
Console.WriteLine( venusAccount.ToString());
Console.WriteLine(jupiterAccount.ToString());
jupiterAccount.TransferTo(venusAccount, 100);
Console.WriteLine("After interface TransferTo...");
Console.WriteLine(venusAccount.ToString());
Console.WriteLine(jupiterAccount.ToString());
Console.ReadLine();
}
}
}
// 接口
namespace Wrox.ProCSharp
{
public interface IBankAccount
{
void PayIn(decimal amount);
bool Withdraw(decimal amount);
decimal Balance
{
get;
}
}
// 接口也可以继承接口
public interface ITransferBankAccount : IBankAccount
{
bool TransferTo(IBankAccount destination, decimal amount);
}
}
namespace Wrox.ProCSharp.VenusBank
{
public class SaverAccount : IBankAccount
{
private decimal balance;
public void PayIn(decimal amount)
{
balance += amount;
}
public bool Withdraw(decimal amount)
{
if (balance >= amount)
{
balance -= amount;
return true;
}
Console.WriteLine("Withdrawal attempt failed.");
return false;
}
public decimal Balance
{
get
{
return balance;
}
}
public override string ToString()
{
return String.Format("Venus Bank Saver: Balance = {0,6:C}", balance);
}
}
}
// 实现类要实现所有接口的函数声明
namespace Wrox.ProCSharp.JupiterBank
{
public class CurrentAccount : ITransferBankAccount
{
private decimal balance;
public void PayIn(decimal amount)
{
balance += amount;
}
public bool Withdraw(decimal amount)
{
if (balance >= amount)
{
balance -= amount;
return true;
}
Console.WriteLine("Withdrawal attempt failed.");
return false;
}
public decimal Balance
{
get
{
return balance;
}
}
// 接口的解耦实现,不需要知道接口子类太多细节
public bool TransferTo(IBankAccount destination, decimal amount)
{
bool result = Withdraw(amount);
if (result)
{
destination.PayIn(amount);
Console.WriteLine("Call TransferTo Success. Transfer from " + this.GetType() + " to " + destination.GetType() );
}
else
{
Console.WriteLine("Call TransferTo Failed.");
}
return result;
}
public override string ToString()
{
return String.Format("Jupiter Bank Current Account: Balance = {0,6:C}", balance);
}
}
}
5.结构体是值类型的存放在栈中,可以有函数,成员有访问类型,不可继承,提供默认构造函数初始化不能被替换。
需要用new调用默认构造函数初始化但还是在栈中,结构有速度快的方面就是内存分配,慢的方面是结构体作为参数拷贝,可以声明为ref引用避免拷贝,但是这样会改变结构体的值。结构除了自动继续自valuetype类,不允许派生类,结构不能重写无参构造函数。
6.类和结构区别
堆和栈存储区别,尽管结构体也是new出来的,但是还是在堆栈上,而不是对象的堆上。
可以继承类和不能继承区别,结构不能继承也不能被继承类和结构,但是结构可以继承接口。
联系: 都有访问特性,都需要new创建且会赋予初始化值0。
结构new出来还是在栈中分配内存块,结构体作为参数用ref性能更好,但是会改变原来的值。
结构体不能提供默认的构造函数,系统会为所有值成员默认值,所有引用成员赋值null。
函数参数传值是默认的,基本类型拷贝一份值;引用类型拷贝的只是引用;字符串不能像一般引用一样因为是字符串常量处理每次都会拷贝一份改变不会反映出来。
联系: 都有访问特性,都需要new创建且会赋予初始化值0。
结构new出来还是在栈中分配内存块,结构体作为参数用ref性能更好,但是会改变原来的值。
结构体不能提供默认的构造函数,系统会为所有值成员默认值,所有引用成员赋值null。
7.方法传入参数默认值类型,改引用要ref且初始化, 字符串会被拷贝一份
要将值类型传值改为传引用定义函数需要加ref标志,调用时候也要加ref标志。
最后强调传递给函数的参数都要初始化无论是值类型还是字符串类型。
out修饰的函数定义,传入时候可以不用初始化,调用时候需要同样的out声明,虽然初始化的引用类型也可以做到但是会导致不必要的误解。
最后强调传递给函数的参数都要初始化无论是值类型还是字符串类型。
8.方法输出参数标志out指定,不用初始化
9.方法参数调用顺序,默认参数值在最后,方法重载和cpp一样
参数的调用顺序调用时候可以用名字限定而不需要按次序调用。默认参数值只能在最后面不能在前面。支持方法重载和cpp一样规则。
属性是对一个字段自动设置getXX,setXX方法,但用的时候一定要以字段形式使用,属性类型就是get/set方法传入和传出参数的类型,一定要有一个访问方法类型和属性访问类型一样没有则是属性的类型,可以不用字段如果没有其它逻辑,不用字段时get/set有控制属性需要一起设置,属性或者简单调用的函数会被CRL编译为内联函数不用程序员操作。
属性在于更方便的封装数据,取值赋值点单一,易于定位问题,更加符合面向对象对修改关闭对拓展开放原则。
与字段不同,属性不作为变量来存储。因此,不能将属性作为 ref参数或 out参数传递。
// C#3.0以后可以不用字段名,直接写属性及取值设置声明,CRL会自动生成属性字段由CRL生成,例如.field private string '<Name>k__BackingField'
// 需要同时提供默认的get;set;访问器,实际开发中很多应用,简化代码。
索引器:
索引器必须为只读-只能是查询,并且你不能使用 get 取值函数关键字。
var和new类型在一起,可以创建一个匿名类型,var声明的是一个继续自object但是不知道类名的类型,new出来的是一个数组类型的的结构。
10.属性就是CRL自动生成的方法,是方法但类似数据成员一样使用 / 索引器定义和使用时候多了参数索引
属性在于更方便的封装数据,取值赋值点单一,易于定位问题,更加符合面向对象对修改关闭对拓展开放原则。
与字段不同,属性不作为变量来存储。因此,不能将属性作为 ref参数或 out参数传递。
// 只读属性,封装了外部的设值
class Employee
{
private string name;
public string Name
{
get
{
return name != null ? name : "NA";
}
}
}
// 抽象类中只定义接口:
abstract class Shape
{
public abstract double Area
{
get;
set;
}
}
class Square : Shape
{
public double side;
public Square(double s) //constructor
{
side = s;
}
public override double Area
{
get
{
return side * side;
}
set
{
side = System.Math.Sqrt(value);
}
}
}
// C#3.0以后可以不用字段名,直接写属性及取值设置声明,CRL会自动生成属性字段由CRL生成,例如.field private string '<Name>k__BackingField'
// 需要同时提供默认的get;set;访问器,实际开发中很多应用,简化代码。
索引器:
-
使用索引器可以用类似于数组的方式为对象建立索引。
-
get 取值函数返回值。set取值函数分配值。
-
this 关键字用于定义索引器。
-
value 关键字用于定义由set 索引器分配的值。
-
索引器不必根据整数值进行索引;由你决定如何定义特定的查找机制。
-
索引器可被重载。
-
索引器可以有多个形参,例如当访问二维数组时。
class SampleCollection<T>
{
// Declare an array to store the data elements.
private T[] arr = new T[100];
// Define the indexer, which will allow client code
// to use [] notation on the class instance itself.
// (See line 2 of code in Main below.)
public T this[int i]
{
get
{
// This indexer is very simple, and just returns or sets
// the corresponding element from the internal array.
return arr[i];
}
set
{
arr[i] = value;
}
}
}
// This class shows how client code uses the indexer.
class Program
{
static void Main(string[] args)
{
// Declare an instance of the SampleCollection type.
SampleCollection<string> stringCollection = new SampleCollection<string>();
// Use [] notation on the type.
stringCollection[0] = "Hello, World";
System.Console.WriteLine(stringCollection[0]);
}
}
// Output:
// Hello, World.
直接只返回表达式结果的索引器很常见。 下面的语法快捷方式使用 => 来定义这些索引器:
public Customer this[long id] => store.LookupCustomer(id);
索引器必须为只读-只能是查询,并且你不能使用 get 取值函数关键字。
11.var和new在一起可以创建匿名类型
// 相当于匿名类型,实例化时候CRL推断出类型,推断出来后就被确立了
var person = new {FirstName = "Sam", MiddleName = "Jia" LastName = "Cen"};
var doctor = new {person.FirstName, person.MiddleName, person.LastName};
doctor.LastName = "Ou";
person = doctor;