我的天空,我的世界

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

参数传递(ref、out、params):
1.当按引用方式(方法中对参数的更改将反映在该变量中)传递参数时,方法定义和调用方法都需显示地使用ref关键字。ref传递的参数变量须在传递前初始化
2.通过out关键字可以引用方法中的变量,方法定义和调用方法都需显示地使用out关键字
3.当要传入未知个数的同类型参数,可以使用params。如:void Average(params double[] x)

循环控制:
1.foreach迭代语句中不能对集合修改,要修改就要使用for遍历
2.do-while和while的区别是do-while至少执行一次执行体。
3.continue关键字作用是跳过循环体中剩余语句而执行下一次循环。对于while和do-while循环,continue是跳到条件判断表达式,对于for循环是跳到循环变量计算表达式(如i++)

数组:
1.数组定义和初始化:int[] 一维数组=new int[3]; int[] 一维数组={1,2,3}; int[] 一维数组=new int[3]{1,2,3};
                            int[,] 二维数组=new int[2,3];int[,] 二维数组={{1,2,3},{3,4,5}}
                            int[,,] 多维数组=...
                            int[][] 交错数组=new int[][]{new int[]{1,2},new int[]{3}};int[][] 交错数组=new int[2][]
 

访问修饰符:
1.publice:公共,在任何地方都可访问
2.private:私有,只能在本作用域中访问
3.protected:受保护,本类和派生类可访问
4.inernal:内部,本程序集中任何地方可访问

 

类型转换:
1.三种显式转换方式:a.“(数据类型)”形式--只支持兼容类型(比如都是数值类型)之间的强制转换
                            b.“Convert.To..”--支持的数据类型更广一些
                            c.“基础数据类型.Parse”--每种基本数据类型都带Parse方法,用于将字符串转成对应的数值类型

 

运算符重载和转换运算符(operator、implicit、explicit):
1.implicit用于隐式转换的实现,定义为:
public static implicit operator targetType(sourceType o)
explicit用于显示转换,定义为:
publice static explicit operator targetType(sourceType o)
2.这两种转换运算符主要用于自定义类与其他类型的转换,换句话说无法在内置类型之间重新定义类型转换,因此targetType和sourceType中至少有一个必须是用户定义的类型。另外,基类与其派生类之间也不能重新定义转换,因此object类不能被自定义转换

转换运算符
 1 class ConverOper
 2     {
 3         static void Main(string[] args)
 4         {
 5             long lngArea;
 6             clsRectangle myclsRectangle = new clsRectangle(1510);
 7             Console.WriteLine
 8                 ("以下将类对象myclsRectangle转换成为lngArea,此为隐式转换!\n");
 9             //由于存在隐式转换的实现定义,将clsRectangle类对象指定给long类型变量时,
10             //自动转换为矩形面积值。如果矩形面积值超过long类型的允许值,则不能隐式转换
11             lngArea = myclsRectangle;
12 
13             Console.WriteLine
14                 ("lngArea的值等于myclsRectangle的面积:{0}\n",lngArea);
15             Console.WriteLine
16                 ("以下将类对象myclsRectangle转换成为mySqure,此为强制转换!\n");
17            
18             clsSquare mySquare = (clsSquare)myclsRectangle;
19             lngArea = mySquare.lngArea;
20             Console.WriteLine
21                 ("lngArea的值等于mySquare的面积:{0}\n", lngArea);
22             Console.ReadLine();
23         }
24         class clsRectangle
25         {
26             int intWidth;
27             int intLength;
28             public int intArea;
29             public clsRectangle(int x, int y)
30             {
31                 intWidth = x;
32                 intLength = y;
33                 intArea = intWidth * intLength;
34             }
35             public static implicit operator long(clsRectangle oclsRectangle)
36             {
37                 long lngArea;
38                 lngArea = oclsRectangle.intArea;
39                 return lngArea;
40             }
41             public static explicit operator clsSquare(clsRectangle oclsRectangle)
42             {
43                 int intWidth;
44                 intWidth = oclsRectangle.intWidth;
45                 clsSquare myclsSquare = new clsSquare(intWidth);
46                 return myclsSquare;
47             }
48         }
49 
50         class clsSquare
51         {
52             int intWidth;
53             public long lngArea;
54             public clsSquare (int x)
55             {
56               intWidth =x;
57               lngArea =x*x;
58             }
59          }
60     }

 

类、方法、重载(static、override、new、virtual、partial):
1.类默认的访问限定是internal,类里的成员默认访问限定是private。
2.静态类的成员必须都是静态的,而且不能有构造函数。普通类里可以有静态成员,为了阻止实例普通类,可以讲普通类的构造函数设置为private.
3.静态方法中不能访问非静态的类成员,非静态方法和非静态数据成员。但非静态成员方法中可以任意访问静态成员
4.方法重载必须是同一个类中的方法。满足名字相同,参数不同。当根据参数没有找到对应的方法时,c#将调用“最近”类型参数的方法。所谓“最近”规则即隐式转换,不能隐式转换时则报错
5.virtual 方法,除了表示可在子类中重写外,和普通方法完全一样。
abstract方法,只能出现在抽象类中,并且必须在子类重写。
extern方法,表示方法的代码体可以放在其他地方
6.在子类里用new隐藏了父类中的方法后,通过多态调用被重写的方法,可以执行父类里原来的方法。
在子类里用override重写父类中的方法后,通过多态调用被重写的方法,只能执行子类里重写的方法。
7.分部类允许将类代码放在多个文件中,所有部分都必须有相同的可访问性,如都是public、private。

构造方法:
1.构造方法允许是静态的。静态构造函数既无访问修饰符、无参数;在第一次 new 或第一次调用任何静态成员之前,将自动调用静态构造函数;静态构造函数一般用于初始化静态数据;不能直接调用静态构造函数。一旦父类里有静态构造函数,子类里就不可有无参的构造函数。无论创建几个包涵静态构造函数的类实例,静态构造函数只会被执行一次。
2.只要类中存在一个自定义的构造方法,系统将不再提供默认构造方法。此时如果不单独定义无参数的构造方法,将不能通过“new classname()"的方法创建对象实例。
3.可以通过base(父类构造函数对应的参数),来指定实例子类时调用的父类构造函数。也可通过this(当前类其他构造函数对应的参数),来指定实例子类时调用的自己的其他构造函数。

析构方法:
1.一个类只能有一个析构方法,析构方法定义规则和构造方法几乎相同,只是在构造方法前加“~”
2.无法继承或重载析构方法
3.无法自己调用析构方法,它们是被自动调用的
4.析构方法不用任何访问修饰符,也没有参数

属性:
1.属性不一定要和数据成员绑定
2.属性绑定的数据成员不受限制,但是最好从属性名能直接看出它是和哪个数据成员关联的
3.属性可以是静态的,使用起来和静态方法一样
4.get和set访问器可以有各自的访问修饰符,但一般都不用,默认是public类型

索引器:

private string[] names=new string[5];
public string this[int n]
{
get{return names[n];}
 
set{names[n]=value;}
}

1.索引器是属性的一种,this关键字用于定义索引器
2.value关键字代表由set索引器获得的值
3.索引器不一定根据整数值索引,由你决定索引器参数的类型
4.索引器的[]里面可以是任意参数列表
5.索引器可被重载

继承(:):
1.protected的成员可在子类内部使用,但是不能被子类对象obj调用。只有public和internal的成员可以被对象在外部调用。在创建子类对象时,实际上父类的对象先被创建,然后是子类对象,内存中有两个对象。
2.通过base关键字可以指定调用的父类构造方法,缺省是base() 。base关键字还可用于引用父类的非私有成员。例如:base.fatherclassmethod()

抽象类(abstract):
1.抽象类不能直接使用new关键字创建实例。抽象方法不需要方法体,而抽象属性和索引器需要空方法体。
2.继承了抽象类的非抽象子类必须重写抽象类里的所有抽象方法。这是抽象基类的对象就可以引用子类实例的这个方法了。

Person p=new Employee();//抽象类Person对象引用子类实例
p.Name="ealge"; //现在抽象类的对象可以引用子类里被重写的成员了

3.使用virtual关键字可以在普通类里创建虚方法(类似抽象方法,必须被override,不流行了)。抽象方法的修饰符不能是私有的,也不能是静态的。

接口(interface):
1.接口很像只包含抽象方法的抽象类。接口不能包含字段,可以包含方法、属性和索引器。成员不能有访问修饰符,默认访问修饰符是public。也不能用static。
2.继承了接口的类必须用public修饰符实现接口里的方法,但不需要使用override。
3.如果类继承了两个接口中有同名的方法,则需使用显示接口实现语句,而且不能为public了。

委托(delegate):[访问修饰符]delegate 返回值类型 委托类型名称(参数列表)
1.委托返回值类型和参数列表决定了委托能够代表的方法。

委托示例

2.多播委托

Code

3.多播委托的委托方法最好是没有返回值的,因为只有最后一个委托方法的返回值才能被返回。
4.多播委托只支持+、-、+=、-=四种运算。
5.匿名方法就是把方法体移到委托对象的赋值表达式右边。Say sayhello=delegate(){Console.Write("hello!");}
  使用匿名方法,系统不必编译和创建单独的方法,因此效率较高。

 

事件(event):[访问修饰符]event委托类型 事件变量
1.

Code

 

Code

枚举(enum):
1.const和readonly都可用来定义常量。区别是readonly定义的常量可以在运行时再赋值,如:public readonly DateTime j = DateTime.Now;另外还可以在构造方法里修改。
2.c#中const只能修饰字段和局部变量,不能修饰方法。
3.枚举中的每个元素实际都是“符号/值”类型,默认第一个元素值是0,可以指定除了Char外的任何整型。


using system;
namespace MyNameSpace
{
  
enum Colors{Red=1,Green=2,Blue=4,Yellow=8};
  
class Program
  {
    
public static void Main(string [] args)
    {
        
//提取枚举成员中的数字,为“1”
        int ncolor=(int)Colors .Red ;
        
//提取枚举成员的名字,为“Red”
        string strcolor=Colors.Red.ToString();
        
//定义一个枚举对象
        Colors cs=Colors.Red ;
        
//遍历枚举
        foreach(string s in Enum .GetName (typeof (Colors )))
            Console.WriteLine (s);
        
//将字符串转换成枚举对象
        cs=(Colors )Enum.Parse(typeof(Colors),"Blue");
    }
  }
}

结构(struct):
1.结构可以视为轻量类,不能是抽象的,不能继承。
2.结构类型是值类型, 值类型定义后就会分配内存,而引用类型是动态分配内存。因此不宜定义复杂和大型的结构。不过值类型效率比较高。
3.编译器始终为结构提供一个默认的无参数构造方法,它是不能自定义的。

密封(sealed):
1.密封类除了不能作基类而被继承,也不能是抽象的,其他和普通类一样。
2.在子类里重写过的方法、字段、属性或事件,可以声明为密封成员,sealed关键字置于override前面。但以后的派生类里就不可以再次重写了。

可空类型(?):
1.可空类型的定义语法是"数据类型?",表示其基础值类型正常范围内的值再加上一个null值。主要用于数据库编程。
2.可空类型支持"??"运算符。"??"可以在将可空类型分配给非可空类型时返回的默认值。可空类型如果有值那么可以强行转换成对应值类型,或者也可用其Value属性直接赋值给同类值类型。使用可空类型的HasValue属性可以先判断是否有值

可空类型示例

 

is和as运算符:
1.is检查某个对象是否与给定类型兼容,兼容是指是该类型或是派生于该类型的子类型。
2.as用于在兼容的引用类型之间执行类型转换。as与强制转换的区别是当转换失败时,运算符返回"null",而不是引发异常。
3.as等效于string str=os is string ?(string)os:null;

数学类(Math):

方法

说明

方法

说明

Abs

求绝对值

Pow

xy次幂

Max

求较大的一个

Round

求四舍五入后的值

Min

求较小的一个

Truncate

求数字的整数部分

Sqrt

求平方根

PI

返回PI

Floor

求小于或等于该数的最大整数

Cos

求余弦值

Ceiling

求大于或等于该数的最小整数

Sin

求正弦值

Exp

e的指定次幂

Tan

求正切值



结构化异常处理(try,catch,finally,throw):
1.异常结构至少有一个try或一个catch或一个finally。try块中一般是较易出错或要求执行特殊资源释放的代码块。
2.catch块如果有多个,那么系统捕获到异常后会从上向下匹配。匹配成功,就将捕获到的异常对象赋值给这个catch后面的异常对象,并执行此catch块里的代码。执行后不再执行其他catch块。必须先捕捉派生类异常,然后再捕捉基型异常。不用优先捕捉Exceptin类异常。
3.finally块里的代码最终都会被执行。里面一般放置一些重要资源的释放和清理代码。比如文件资源、窗口资源、数据连接、网络连接等。
4.要捕获多个异常,可以使用嵌套异常结构。或配合使用判断和抛出异常throw。

Code

5.自定义异常类可以提供更多信息和功能,一般要写成和系统异常类类似的名字,即以Exception结尾 。选择哪个系统异常类继承需要考虑好,尽量不要引起误解。

自定义异常验证邮件地址是否合法

6.异常的一些属性可以提供很多调试信息
TargetSite--获取引发当前异常的方法及该方法所在的类和成员属性等信息
StackTrace--确定错误发生位置的堆栈跟踪,包含源文件名和程序行号,对调试很有帮助
HelpLink--可用于保存某个帮助文件的URL或URN,该帮助文件通常提供异常的大量信息
Data--可以以键值对形式保存任意的数据,其类型为IDictionary,方便后续处理

using的三个用法:
1.using + 命名空间名字
2.using别名。using + 别名 = 包括详细命名空间信息的具体的类型。
这种做法有个好处就是当同一个cs引用了两个不同的命名空间,但两个命名空间都包括了一个相同名字的类型的时候。当需要用到这个类型的时候,就每个地方都要用详细命名空间的办法来区分这些相同名字的类型。而用别名的方法会更简洁,用到哪个类就给哪个类做别名声明就可以了。注意:并不是说两个名字重复,给其中一个用了别名,另外一个就不需要用别名了,如果两个都要使用,则两个都需要用using来定义别名的。

using定义命名空间别名
3.using关键字定义的语句块执行完成后,块内的资源全部自动释放。
using (Class1 cls1 = new Class1(), cls2 = new Class1())
{
// the code using cls1, cls2} // call the Dispose on cls1 and cls2

 

多线程(Thread):
1.创建线程的方式是:Thread ThreadName=new Thread(new ThreadStart(方法名))
2.可以为线程指定由ThreadPriority枚举定义的优先级,不过优先级设置有时不起作用,比如belownormal 有时比normal执行的快
3.线程的状态有:Aborted、AbortRequested、Background、Running、Stopped、StopRequested、Suspended、Unstarted、WaitSleepJoin。主线程退出时会自动关闭后台线程,否则需要手动关闭。
4.线程的同步基元有:Monitor、Mutex、ReaderWriterLock、Semaphore、AutoResetEvent、ManualResetEvent。ReaderWriterLock在锁定资源写访问频率较低、持续时间也比较短的情况下的性能最好。AutoResetEvent事件在发送给等待线程以后,该事件会在终止时自动重置,而ManualResetEvent必须手动重置。 

使用Lock关键字
class Program
    {
        
static string buffer = "0";
        
private const long Max = 1000000;
        
//锁对象,起到一把锁的作用
        private object myLock = new object();
        
static void Main(string[] args)
        {
            Program test 
= new Program();
            Thread threadA 
= new Thread(new ThreadStart(test.ThreadADoWork));
            threadA.Start();
            Thread threadB 
= new Thread(new ThreadStart(test.ThreadBDoWork));
            threadB.Start();
            threadA.Join();
            threadB.Join();
            Console.WriteLine(
"结果是:{0}", buffer);
        }
        
void ThreadADoWork()
        {
            
for (long i = 0; i < Max / 2; i++)
                
lock (myLock) { buffer = (long.Parse(buffer) + i).ToString(); }
        }
        
void ThreadBDoWork()
        {
            
for (long i = Max / 2; i <= Max; i++)
                
lock (myLock) { buffer = (long.Parse(buffer) + i).ToString(); }
        }
    }

 5.Lock实际是封装了Monitor的操作,使用更简单。Monitor还有个TryEnter的方法,区别是不管得不得到锁都立即返回,不会一直等待。 

Monitor
        Monitor.Enter(buffer)
        
try 
        {            
        
//锁定代码块
        }
        Finally
        {        
        Monitor.Exit(buffer)
//放在finally里可以保证出现异常时也能释放锁
        }
*********  等同于  *************************
        Lock(buffer){
//锁定代码块}

 6.AutoResetEvent常用的方法有:Set、Reset、WaitOne、WaitAny、WaitAll 

AutoResetEvent
class MyMainClass
{
    
//创建一个事件变量,初始状态为无信号
    static AutoResetEvent myResetEvent = new AutoResetEvent(false);
    
static int number;
    
static void Main()
    {
        
//建立一个读数字线程.
        Thread myReaderThread = new Thread(new ThreadStart(MyReadThreadProc));
        myReaderThread.Name 
= "读线程";
        myReaderThread.Start();
        
for (int i = 1; i <= 5; i++)
        {
            Console.WriteLine(
"写线程写的值是: {0}", i);
            
//写入整型变量
            number = i;
            
//发送一个信号给读线程
            myResetEvent.Set();
            
//给读线程一个操作时间,好比红绿灯切换要给车辆通过的时间
            Thread.Sleep(1);
        }
        
//终止读线程
        myReaderThread.Abort();
    }
    
static void MyReadThreadProc()
    {
        
while (true)
        {
            
//停止往下执行直到信号到来
            myResetEvent.WaitOne();
            
//信号来了后执行的读操作
            Console.WriteLine("{0} 读到的值是: {1}", Thread.CurrentThread.Name, number);
        }
    }
}

 

 

AutoResetEvent-WaitAll
class Person
{
    
//建立事件数组
    AutoResetEvent[] autoEvents;
    
public Person()
    {
        
//初始化事件数组
        autoEvents = new AutoResetEvent[]
            {
                
new AutoResetEvent(false),
                
new AutoResetEvent(false),
                
new AutoResetEvent(false)
            };
    }
    
public void GetCar()
    {
        Console.WriteLine(
"捡到宝马");
        autoEvents[
0].Set();//发送得到车子信号
    }
    
public void GeHome()
    {
        Console.WriteLine(
"赚到房子");
        autoEvents[
1].Set();//发送得到房子信号
    }
    
public void GetWife()
    {
        Console.WriteLine(
"骗到老婆");
        autoEvents[
2].Set();//发送得到妻子信号
    }
    
public void ShowHappiness()
    {
        Console.WriteLine(
"生活原来如此美好");
    }
    
static void Main()
    {
        
//进入主线程
        Person p = new Person();
        
//设置三个线程分别来得到房子、车子、妻子
        Thread th1 = new Thread(new ThreadStart(p.GetCar)); th1.Start();
        Thread th2 
= new Thread(new ThreadStart(p.GeHome)); th2.Start();
        Thread th3 
= new Thread(new ThreadStart(p.GetWife)); th3.Start();
        
//等待事件数组中所有信号到齐,才会继续往下执行
        AutoResetEvent.WaitAll(p.autoEvents);
        p.ShowHappiness();
    }
}

7.系统创建线程和切换线程会降低性能,使用线程池自动管理线程可以改善性能。可以通过IsThreadPoolThread判断一个线程是否是线程池里的线程。由于线程池的特性,它不适合以下需求:
a.需要前台线程;
b.需要设定线程的优先级;
c.由于线程池有最大线程数限制,线程池里的线程任务不能是会长时间被阻止的;
d.需要具有与线程关联的属性或使某一线程专用于某一任务时。
创建线程池线程队列的语法是:ThreadPool.QueueUserWorkItem(WaitCallback callback,Object state);其中callback是要执行的方法代理,state是可选项,代表方法需要引用的参数 

ThreadPool
    class ClsThreadPool
    {
        
static void Main(string[] args)
        {
            Console.WriteLine(
"以下开始将工作排入线程管理队列");
            Console.WriteLine(
"******************************");
            
for (int i = 0; i < 4; i++)
            {
                WaitCallback myWaitCallback 
= new WaitCallback(WorkItem);
                ThreadPool.QueueUserWorkItem(myWaitCallback, i 
+ 1);
                Thread.Sleep(
1000);
            }
            Console.WriteLine(
"******************************");
            
for (int i = 0; i < 4; i++)
            {
                WaitCallback myWaitCallback 
= new WaitCallback(LongWorkItem);
                ThreadPool.QueueUserWorkItem(myWaitCallback, i 
+ 1);
                Thread.Sleep(
1000);
            }
            Console.ReadLine();
        }
        
static void WorkItem(object i)
        {
            
string itemName;
            itemName 
= "使用的线程编号Thread ID="
                
+ Thread.CurrentThread.GetHashCode();
            Console.WriteLine(
"这是队列中第1组第{0}个工作,{1}",i,itemName);
            Console.WriteLine(
"此工作线程结束!");
            
//由于没有暂停,执行速度够快,线程池只使用了一个线程先后完成四个工作
        }
        
static void LongWorkItem(object i)
        {
            
string itemName;
            itemName 
= "使用的线程编号Thread ID="
                
+ Thread.CurrentThread.GetHashCode();
            Console.WriteLine(
"这是队列中第2组第{0}个工作,{1}", i, itemName);
            Console.WriteLine(
"此工作线程暂停10秒!");
            
//由于暂停了10秒,线程池为4个工作创建四个线程
            Thread.Sleep(10000);
        }
    }

8.静态方法Synchronized可以创建线程安全的集合,但是容易造成死锁。适合用于集合对象较少的项目。最佳方案是使用SyncRoot 

线程安全的集合
public class SamplesArrayList
{
    
//线程访问的集合
    static ArrayList myAL = new ArrayList();
    
//线程访问的集合安全包装
    static ArrayList sfAL = ArrayList.Synchronized(myAL);
    
public static void Main()
    {
        Thread T1 
= new Thread(new ThreadStart(Write));
        T1.Start();
        Thread T2 
= new Thread(new ThreadStart(Read));
        T2.Start();
    }
    
public static void Write()
    {
        
while (true)
        {
            
//锁定集合进行操作
            lock (myAL.SyncRoot)
            {
                myAL.Add(DateTime.Now.ToString());
            }
        }
    }
    
public static void Read()
    {
        
while (true)
        {
            
//锁定集合进行操作
            lock (sfAL.SyncRoot)
            {
                
foreach (object obj in myAL)
                    Console.WriteLine(
"读: {0} ", obj.ToString());
            }
        }
    }
}

9.Abort方法可以正常退出线程。Interrupt方法是强制退出线程,可能产生一个ThreadInterruptedException的异常 

 

集合对象(Array、ArrayList、Hashtable、):
Array本身是抽象类,只能通过数组的静态方法CreateInstance创建实例。该方法可以创建多维数组,甚至下标不从零开始的数组 

代码
static void Main(string[] args)
        {   
//第一维2个元素,第二维3个元素
            int[] lengths = new int[2] { 23 };
            
//第一维下标从1开始,第二维下标从2开始
            int[] starts = new int[2] { 12 };
            Array name 
= Array.CreateInstance(typeof(int), lengths, starts);
        }

 

ArrayList可以定义非固定长度的数组,可以同时添加、插入或移除一个范围内的元素,但是只能是下标从零开始的一维数组,执行效率也比数组低。ArrayList有个容量的概念,容量表示能装多少元素,元素个数表示现在已装了多少元素。当元素个数超过时会自动增加容量,一般是自动增加一倍。
DictionaryEntry可以类似Hashtable,存放键/值对成员,由于Hashtable 只能通过键的哈希代码对元素进行排序,所以一般要结合ArrayList来间接排序  

代码
static void Main(string[] args)
        {
            
//创建Hashtable集合
            Hashtable ht = new Hashtable();
            
//向集合中添加键/值对
            ht.Add("BENZ""奔驰");
            ht.Add(
"BMW""宝马");
            
//假如集合中没有键"CADILLAC"则添加元素
            if (!ht.Contains("CADILLAC")) ht.Add("CADILLAC""凯迪拉克");
            
//假如集合中没有值"丰田"则添加元素
            if (!ht.ContainsValue("丰田")) ht.Add("TOYOTA""丰田");
            
//显示元素个数
            Console.WriteLine("目前元素个数:{0}", ht.Count);
            Console.WriteLine(
"目前元素有:");
            
//遍历元素
            foreach (DictionaryEntry de in ht)
                Console.WriteLine(
"Key=\"{0}\"\tValue=\"{1}\"", de.Key, de.Value);
            
//删除元素
            ht.Remove("BENZ");
            
//利用ArrayList对Hashtable键集合进行排序
            ArrayList aKeys = new ArrayList(ht.Keys);
            aKeys.Sort();
            
//遍历元素
            Console.WriteLine("排序后元素:");
            
foreach (string key in aKeys)
                Console.WriteLine(
"Key=\"{0}\"\tValue=\"{1}\"", key, ht[key].ToString());
            
//删除所以集合元素
            ht.Clear();

        }

 Icollection接口包含Count、IsSynchronized、SyncRoot、CopyTo
Ienumerable接口包含Current、MoveNext、Reset
Ilist接口包含IsReadOnly、IsFixedSize、Item、Add、Clear、Contains、Indexof、Insert、Remove、RemoveAt
自定义集合类必须实现继承接口的所有成员方法。如果继承了Ilist,还需重写IConnection和IEnumerable里的方法(由于Ilist继承自这两个接口)

栈Stack实现先入后出(Push、Pop),队列Queue实现先入先出(Dequeue、Enqueue)
SortedList是哈希表和数组的杂交,其元素既可通过其键来访问,也可通过索引访问(GetKey、GetByIndex、IndexOfKey、IndexOfValue)
字符串集合StringCollection和StringDictionary的元素不是Object类型,而是string类型

 

泛型:
1.常用的泛型约束有:T:struct、T:class、T:类名、T:接口名、T:U。可以同时设定多个约束,用逗号分隔。 

 

组件技术
使用反射之前需使用System.Reflection下的Assembly类的Load和LoadFrom方法加载程序集。Load方法加载的话,需先将程序集文件dll复制到当前项目exe文件所在目录下(如果是强名称程序集就不必复制了)。加载后,用GetType或GetTypes获得加载程序集的类型。获得类型后,用Activator.CreateInstance()重建类型对象。现在就可用Type类的一些方法获取此类型对象对应的属性或执行对象的方法了。 

代码
 1 class Program
 2 {
 3     class Person
 4     {
 5         public string name;
 6         private static int age;
 7         public Person(string nm, int ag)
 8         {  name = nm; age = ag;    }
 9         public string Name
10         {
11             get { return name; }
12             set { name = value; }
13         }
14         public int Age
15         {
16             get { return age; }
17             set { age = value; }
18         }
19         public void Say(string msg)
20         {  Console.WriteLine("{0}说:{1}", name, msg);    }
21         public void SayHello()
22         {  Console.WriteLine("{0}说:Hello!", name);      }
23     }
24     static void Main(string[] args)
25     {
26         //获取类型
27         Type t = typeof(Person);
28         //创建类型对应的对象
29         object obj = System.Activator.CreateInstance(t, new object[] { "翠花"18 });
30         //获取类型的公共字段
31         FieldInfo[] fields = t.GetFields();
32         foreach (FieldInfo tf in fields)
33         {  Console.WriteLine("字段{0},值:{1}", tf.Name, tf.GetValue(obj)); }
34         //获取类型的公共属性
35         PropertyInfo[] properties = t.GetProperties();
36         foreach (PropertyInfo tp in properties)
37         {
38             Console.WriteLine("属性{0}:{1}", tp.Name, tp.GetValue(obj, null));
39         }
40         //设置Name属性的值
41         PropertyInfo p = t.GetProperty("Name");
42         p.SetValue(obj, "小芳"null);
43         //获取类型方法信息
44         MethodInfo[] methods = t.GetMethods();
45         foreach (MethodInfo tm in methods)
46         {
47             Console.WriteLine("方法{0}", tm.Name);
48         }
49         //调用类型方法
50         MethodInfo m = t.GetMethod("Say");
51         //如果调用的方法没有参数,则Invoke方法的第二个参数为null
52         m.Invoke(obj, new object[] { "我是一朵花" });
53         m = t.GetMethod("SayHello");
54         m.Invoke(obj, null);
55     }
56 }

 调用API需使用DllImportAttribute标示,同时可使用EntryPoint标记导入方法的名称
 [DllImport("user32.dll", EntryPoint = "MessageBoxA", CharSet = CharSet.Auto)]
如果调用的COM组件不是.Net系统的,则需先用tlbimp.exe工具转换:
tlbimp comsample.dll /out: comsample_clw.dll

 

序列化(Serializable):
1.序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。
2.如果采用BinaryFormatter类或者SoapFormatter类来实现序列化,则一定要给类加上Serializable属性。使用XmlSerializer 类序列化对象时可以不用这个属性另外,如果不想序列化某个字段,可以给其加上NonSerialized属性,这样在序列化时就不会保存这个这个字段的值了,反序列化时该数据将丢失。XmlIgnore属性,和NonSerializable属性类似。Soap命名空间需要手动添加引用

三种序列化和反序列化
 1 using System;
 2 using System.IO;
 3 using System.Runtime.Serialization.Formatters.Binary;
 4 using System.Runtime.Serialization.Formatters.Soap;
 5 using System.Xml.Serialization;
 6 
 7 namespace MySerializeDemo
 8 {
 9     public class Program
10     {
11         [Serializable] 
12         public  class ClsSerializable
13         {
14             public int intNumber = 254;
15             public string strDemo = "Hello world!";
16             //[NonSerialized]
17             public long lngNumber = 123456;
18         }
19 
20         static void Main(string[] args)
21         {
22             ClsSerializable obj = new ClsSerializable();
23             Console.WriteLine("========使用BinaryFormatter类进行序列化和反序列化。====");
24             BinarySerialize(obj);
25             BinaryDeserialize("C:\\MyObject.dat");
26             Console.WriteLine("========使用SoapFormatter类进行序列化和反序列化。====");
27             SOAPSerialize(obj);
28             SOAPDeserialize("C:\\MyObject.soap");
29             Console.WriteLine("========使用XmlSerializer类进行序列化和反序列化。====");
30             XMLSerialize(obj);
31             XMLDeserialize("C:\\MyObject.xml");
32         }
33         // 二进制序列化对象   
34         public static void BinarySerialize(ClsSerializable obj)
35         {
36             using (FileStream stream = new FileStream("C:\\MyObject.dat", FileMode.Create, FileAccess.Write))
37             {
38                 BinaryFormatter formater = new BinaryFormatter();
39                 formater.Serialize(stream, obj);
40                 Console.WriteLine("对象已经被序列化。" + obj.ToString());
41             }
42         }
43         // 二进制反序列化   
44         public static void BinaryDeserialize(string fileName)
45         {
46             using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
47             {
48                 BinaryFormatter formater = new BinaryFormatter();
49                 ClsSerializable obj = (ClsSerializable)formater.Deserialize(stream);
50                 Console.WriteLine("对象已经被反序列化。" + obj.ToString());
51             }
52         }
53         // SOAP序列化对象        
54         public static void SOAPSerialize(ClsSerializable obj)
55         {
56             using (FileStream stream = new FileStream("C:\\MyObject.soap", FileMode.Create, FileAccess.Write))
57             {
58                 SoapFormatter formater = new SoapFormatter();
59                 formater.Serialize(stream, obj);
60                 Console.WriteLine("对象已经被序列化。" + obj.ToString());
61             }
62         }
63         // SOAP反序列化   
64         public static void SOAPDeserialize(string fileName)
65         {
66             using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
67             {
68                 SoapFormatter formater = new SoapFormatter();
69                 ClsSerializable obj = (ClsSerializable)formater.Deserialize(stream);
70                 Console.WriteLine("对象已经被反序列化。" + obj.ToString());
71             }
72         }
73         // XML序列化   
74         public static void XMLSerialize(ClsSerializable obj)
75         {
76             using (FileStream stream = new FileStream("C:\\MyObject.xml", FileMode.Create, FileAccess.Write))
77             {
78                 XmlSerializer serializer = new XmlSerializer(typeof(ClsSerializable));
79                 serializer.Serialize(stream, obj);
80                 Console.WriteLine("对象已经被序列化。" + obj.ToString());
81             }
82         }
83         // XML反序列化   
84         public static void XMLDeserialize(string fileName)
85         {
86             using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
87             {
88                 XmlSerializer serializer = new XmlSerializer(typeof(ClsSerializable));
89                 ClsSerializable obj = (ClsSerializable)serializer.Deserialize(stream);
90                 Console.WriteLine("对象已经被反序列化。" + obj.ToString());
91             }
92         }
93     }
94 }

  3.实现Iserializable接口可以自定义序列化行为,继承这个接口类必须实现方法GetObjectData()和构造函数

自定义序列化
 1 using System;
 2 using System.IO;
 3 using System.Runtime.Serialization.Formatters.Binary;
 4 using System.Runtime.Serialization;
 5 
 6 namespace MySerializeDemo
 7 {
 8     public class Program
 9     {
10         [Serializable]
11         public class ClsSerializable : ISerializable
12         {
13             public int intNumber = 254;
14             public string message = "Hello world!";
15             public long lngNumber = 123456;
16             public int[] intArrayX = new int[3];
17             public int[] intArrayY = new int[3];
18 
19             public ClsSerializable()
20             { ChangeMemberValue(); }
21             public void GetObjectData
22                 (SerializationInfo info, StreamingContext context)
23             {
24                 info.AddValue("intNumber", intNumber);
25                 info.AddValue("message", message);
26                 info.AddValue("intArrayX", intArrayX);
27             }
28             public ClsSerializable
29                 (SerializationInfo info, StreamingContext context)
30             {
31                 intNumber = (int)info.GetValue("intNumber"typeof(int));
32                 message = (string)info.GetValue("message"typeof(string));
33                 intArrayX = (int[])info.GetValue("intArrayX"typeof(int[]));
34             }
35             void ChangeMemberValue()
36             {
37                 for (int i = 0; i < 3; i++)
38                 { intArrayX[i] = i * 100; }
39                 intNumber = 2000;
40                 message = "修改过的字符串";
41             }
42         }
43 
44         static void Main(string[] args)
45         {
46             ClsSerializable myClsIS = new ClsSerializable();
47             //序列化
48             FileStream stream = new FileStream("C:\\MyObject.bin", FileMode.Create, FileAccess.Write);
49             BinaryFormatter formater = new BinaryFormatter();
50             formater.Serialize(stream, myClsIS);
51             myClsIS = null;
52             stream.Close();
53             //反序列化
54             stream = new FileStream("C:\\MyObject.bin", FileMode.Open);
55             formater = new BinaryFormatter();
56             myClsIS = (ClsSerializable)formater.Deserialize(stream);
57             stream.Close();
58 
59             Console.WriteLine(myClsIS.message);
60             Console.WriteLine(myClsIS.intNumber);
61             Console.WriteLine(myClsIS.lngNumber);
62             for (int i = 0; i < 3; i++)
63             {
64                 Console.WriteLine(myClsIS.intArrayX[i]);
65             }
66         }
67     }
68 }
69 

 

4.对象的序列化属性不能被继承,也就是说必须在子类明确标注[Serialized],还必须实现GetObjectData()和构造函数
5.对于无法序列化的数据,在反序列化时会丢失数据。为了解决这个问题,可以继承IDeserializationCallback接口,实现方法OnDeserialization还原正确数据
6.XML序列化仅将对象的公共字段、属性值和只读集合序列化为XML流,不包括类型信息,所以要完全序列化,请使用二进制序列化。除非二进制序列化无法穿越防火墙,才考虑使用XML序列化

 

 

 

其他:
1.this关键字只能用在方法、属性、索引器的代码中,不能在构造和析构方法内部使用。this不能引用静态方法或属性。
2.#region 可把一组代码标注为一个有名称的可伸缩的块
3.base关键字用于指定子类调用父类哪一个构造方法,以及调用父类成员
4.default关键字 解决类型参数的默认值 如T para=default(T)表示T是引用类型para的默认值为null,否则为数值0
5.fixed块里的被引用的变量将固定在内存中,不会在重组时被移动
6.unsafe 关键字表示不安全上下文,该上下文是任何涉及指针的操作所必需的

 
volatile

yield

explicit

extern

 

implicit

stackalloc

groble

posted on 2009-10-14 22:15  eaglegrace  阅读(827)  评论(0编辑  收藏  举报