用c#编写程序也有段时间了,但有很多概念其实也搞得不是很清楚,或者只是简单的拷贝一下已有的代码,修修改改也能弄出一个东西,但真正要空手写一个还是有点难度。这几天打算重新好好学习一下最基本的东西。手头有一本Microsoft .NET框架程序设计(修订版)(Jeffrey Richter),要好好重温一下。
1.类型的访问控制(控制由松到严格)
public:可以被任何程序集中的任何代码调用。
internal(assembly,VB中是Friend):可以被同一程序集中的任何代码调用。
protected(Family):可以被同一类型中和派生类型中的代码调用,不能被其他类访问。
private:只能在同一个类型中访问。
默认为internal。
2.new一个对象所进行的操作
a.从托管堆中分配指定类型所需数量字节来作为存储其对象的内存空间
b.初始对象的附加成员。每一个对象都有两个附加成员,CLR使用这两个成员来管理对象。一个为指向类方法表的指针,另一个为SyncBlockIndex。
c.传入new操作符指定的参数,调用构造函数。
3.is操作符和typeof
用来判断某个对象是否某个类型(或基类)。返回true或者false。如果对象为null,则肯定返回false。
bool b =o is object;
而typeof()输入一个类型(而非实例),返回一个system.type的实例。
4.基元类型和FCL类型
基元类型和FCL类型有对应关系。c#语言规范中推荐使用基元类型。但Jeffrey Richter推荐使用FCL类型。
常用的一些对应有
基元类型 FCL类型 备注
byte System.Byte
int System.Int32
long System.Int64
float System.Single
double System.Double
bool System.Boolean
5.装箱和拆箱
装箱就是将值类型转化为应用类型
拆箱则相反
装箱的过程:
a.在托管堆中新生成一个空间,并将值类型的实例所有成员拷贝到这个新的空间
b.返回新开空间的引用
6.类(型)的成员
a.常数:常数是静态的,是属于类的而不是属于实例的,不能用this访问
public const int theConst=0;
b.readonly修饰:readonly修饰的变量是属于实例的,能够在构造函数中修改其值
c.类型构造器(静态构造函数):初始化类型的静态字段。
static classname(){},不能用public等修饰,不能带参数。在类型第一次被访问的时候执行。
d.静态成员(static):属于类型,不属于实例,在静态方法中不能访问非静态成员。在非静态成员中能够访问静态成员,但不能加this
7.类型的预定义特性(abstract,sealed)
abstract(VB:MustInherit):不能被实例化,可以做基类。基类可以被实例化
sealed(VB:NotInheritable):不能作为基类
8.字段和方法的预定义特性
a.字段预定义特性
static(VB:Shared)
readonly
b.方法预定义特性
static(VB:Shared):静态方法,属于类型而非类的实例
virtual(VB:overridable):当方法被调用的时候,按照对象继承链最末端的方法调用。父类的virtual和子类的override配合,就能被继承链的最末端调用,否则会按照编译时的类型调用。要被重写的(override)方法,在基类应该写virtual。
new(VB:Shadows):不重写基类方法
override(Overrides):重写基类方法,与基类的virtual配合
abstract(Mustoverride)
sealed(NotOverridable)
9.委托
委托相当于函数指针,用类型安全的方法来提供函数回调机制。
函数名是一个委托的实例。
a.定义委托类型
在类的内部或者类的外部,地位相当于一种类型。
public delegate void FeedBack(string arg1,string arg2);
其中,void表示该委托类型的返回值,小括号内表示该委托类型的参数
b.定义委托实例
FeedBack fb=new FeedBack(函数名);
或者先定义一个指向null的委托,再往这个委托的委托链上添加函数
FeedBack fb=null;
fb+=函数名;
或者干脆直接用函数名称作为一个委托的实例
FeedBack fb=函数名;
10.类的事件
a:定义一个事件参数类(和该类在同一个命名空间内),继承自EventAgrs
b:定义一个委托类型(和该类在同一个命名空间内) public delegate void EventHandler(object sender,EventArgs e);
c:在类里面定义事件(其实是定义一个委托)
public event EventHandler OnEvent;(event关键字可以省略)
d:引发事件
if(OnEvent!=null)
{
OnEvent(sender,e);
}
如果事件被注册了就不会为null
捕获事件
订阅:对象名.OnEvent+=new EventHandler(处理函数名称);
取消订阅:对象名.OnEvent-=new EventHandler(处理函数名称);
注意:只要一个对象仍然登记有另外一个对象的事件,该对象就不能被执行垃圾回收
所以应该在必要的地方注销所有的事件注册
11.异常处理
异常处理一直是让人感到迷茫的地方,哪里应该捕获异常,哪里不应该捕获异常,捕获的异常应该如何处理,异常对程序性能的影响等等问题,是要搞清楚的问题。
异常是对程序接口隐含假设的一种违反。那么如何通知调用者违反了假设呢?答案就是抛出一个异常。
c#可以只写catch,不写小括号,表示捕捉所有的异常。可以thorw,不写抛出什么异常,代表抛出所捕获的异常。
finally内部的代码用于做一些清理工作(如关闭文件,关闭数据库链接等),即使try里面的代码抛出异常,或者try里面有return,finally的代码也会执行。可以认为向上抛出异常和return是同样级别的,而finally则在它们之前进行运行
12.接口
13.递归的编写
一个递归的类:
public class Node
{
public string Name;
public List<Node> Childs;
}
用一个函数打印这个类:
private void print(Node n)
{
Console.WriteLine(n.Name);
//每层递归的操作
if (n.Childs != null)
{
foreach (Node c in n.Childs)
{
print(c);
}
}
//跳出递归的条件
}
14.继承
问题:当子类实例化的时候,和父类的构造函数有什么关系?如何显式调用父类的构造函数?
15:
c#的一个case中不能像vb那样同时写多个条件,但能够这样写:
switch (afn)
{
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x0A:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x0E:
case 0x0F:
case 0x10:
return (AFNS)afn;
default:
return AFNS.Unknown;
}
(也就是说,如果case中没有语句,就可以不使用break)
16.base 关键字
用于从派生类中访问基类的成员:
a.调用基类上已被其他方法重写的方法。
b.指定创建派生类实例时应调用的基类构造函数。
c.基类访问只能在构造函数、实例方法或实例属性访问器中进行。从静态方法中使用 base 关键字是错误的。
调用基类方法:
public class Person
{
protected string ssn = "444-55-6666";
protected string name = "John L. Malgraine";
public virtual void GetInfo()
{
Console.WriteLine("Name: {0}", name);
Console.WriteLine("SSN: {0}", ssn);
}
}
class Employee : Person
{
public string id = "ABC567EFG";
public override void GetInfo()
{
// Calling the base class GetInfo method:
base.GetInfo();
Console.WriteLine("Employee ID: {0}", id);
}
}
调用基类构造函数:
public class BaseClass
{
int num;
public BaseClass()
{
Console.WriteLine("in BaseClass()");
}
public BaseClass(int i)
{
num = i;
Console.WriteLine("in BaseClass(int i)");
}
public int GetNum()
{
return num;
}
}
public class DerivedClass : BaseClass
{
// This constructor will call BaseClass.BaseClass()
public DerivedClass() : base()
{
}
// This constructor will call BaseClass.BaseClass(int i)
public DerivedClass(int i) : base(i)
{
}
static void Main()
{
DerivedClass md = new DerivedClass();
DerivedClass md1 = new DerivedClass(1);
}
}
dispose与finalize
可参考blog:http://www.cnblogs.com/xlshcn/archive/2007/01/16/idisposable.html
// Design pattern for a base class.
public class Base: IDisposable
{
//Implement IDisposable.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
// Set large fields to null.
}
// Use C# destructor syntax for finalization code.
~Base()
{
// Simply call Dispose(false).
Dispose (false);
}
}
// Design pattern for a derived class.
public class Derived: Base
{
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Release managed resources.
}
// Release unmanaged resources.
// Set large fields to null.
// Call Dispose on your base class.
base.Dispose(disposing);
}
// The derived class does not have a Finalize method
// or a Dispose method without parameters because it inherits
// them from the base class.
}
x.gettype和typeof的用法
1.判断某个实例是否某个类型
c# o is classname
vb typeof o is classname
2.c# typeof(int)
bv gettype(integer)
3.object类的方法
c# o.GetType
vb o.GetType
x.关于类的继承,重写等 (override)