楼主: keaide

C#重点知识详解

[复制链接]
论坛徽章:
456
ITPUB年度最佳版主
日期:2011-12-28 15:24:18马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14ITPUB年度最佳版主
日期:2014-02-19 10:05:27优秀写手
日期:2013-12-18 09:29:09ITPUB社区千里马徽章
日期:2013-06-09 10:15:34ITPUB年度最佳版主
日期:2013-01-30 17:30:25版主9段
日期:2012-07-03 02:21:03
11#
 楼主| 发表于 2006-5-27 21:49 | 只看该作者
第五章:代理
代理实现的是象c++等语言的指针功能,不同于函数指针,代理是一种面向对象、安全类型的。代理事派生于公共基类(system)的一种参考类型,方法被压入一个代理中,对于实例方法被称为实例的组成实体或关于实例的方法,而静态方法,被称为类的组成实体或类方法。代理的强大功能是它可以自动的匹配方法,而不管其类型。

写一个代理包括三个步骤:


写代理、实例化、调用。


代理的声明使用以下语法:
delegate void SimpleDelegate();

实例化一个代理
class Test
{
static void F() {
System.Console.WriteLine("hello world";
}
static void Main() {
SimpleDelegate d = new SimpleDelegate(F);//将方法压入
d();//通过代理;
F();//不通过代理;
}
}

使用道具 举报

回复
论坛徽章:
456
ITPUB年度最佳版主
日期:2011-12-28 15:24:18马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14ITPUB年度最佳版主
日期:2014-02-19 10:05:27优秀写手
日期:2013-12-18 09:29:09ITPUB社区千里马徽章
日期:2013-06-09 10:15:34ITPUB年度最佳版主
日期:2013-01-30 17:30:25版主9段
日期:2012-07-03 02:21:03
12#
 楼主| 发表于 2006-5-27 21:50 | 只看该作者
最后让我们调用她

void MultiCall(SimpleDelegate d, int count) {
for (int i = 0; i < count; i++)
d();
}
}

我们可以看到对于方法的调用是通过代理来完成的,调用时并不需要知道被调用她的类型。代理在我看来好比是对象要一件事她不直接地调用这个方法,而是通过一个中间人去调用她。

下面就代理的强大功能进行详细介绍:首先然我们实现一个这样的功能,考虑一下该如何用指向基类的对象调用子类的成员函数。在这里程序员是不是点怀恋指针了,不过在c#中这样的功能完全也可实现的,使用一个单独的代理我们可以完成这项功能。以下代码来自Timothy A. Vanover文章。

使用道具 举报

回复
论坛徽章:
456
ITPUB年度最佳版主
日期:2011-12-28 15:24:18马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14ITPUB年度最佳版主
日期:2014-02-19 10:05:27优秀写手
日期:2013-12-18 09:29:09ITPUB社区千里马徽章
日期:2013-06-09 10:15:34ITPUB年度最佳版主
日期:2013-01-30 17:30:25版主9段
日期:2012-07-03 02:21:03
13#
 楼主| 发表于 2006-5-27 21:51 | 只看该作者
namespace DelegatesCS
{
using System;

public class Wisdom //包含代理的类
{
public delegate string GiveAdvice();
public string OfferAdvice(GiveAdvice Words)
{
return Words();
}
}
public class Parent //基类
{
public virtual string Advice()
{
return("Listen to reason";
}
~Parent() {}
}
public class Dad: Parent //子类
{
public Dad() {}
public override string Advice()
{
return("Listen to your Mom";
}
~Dad() {}
}
public class Mom: Parent //子类
{
public Mom() {}
public override string Advice()
{
return("Listen to your Dad";
}
~Mom() {}
}
public class Daughter //不继承与基类的类
{
public Daughter() {}
public string Advice()
{
return("I know all there is to life";
}
~Daughter() {}
}


public class Test
{
public static string CallAdvice(Parent p)//使用基类
{
Wisdom parents = new Wisdom();
Wisdom.GiveAdvice TeenageGirls = new Wisdom.GiveAdvice(p.Advice);//将Advice方法委托给TeenageGirls委托对象
return(parents.OfferAdvice(TeenageGirls));
}

使用道具 举报

回复
论坛徽章:
456
ITPUB年度最佳版主
日期:2011-12-28 15:24:18马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14ITPUB年度最佳版主
日期:2014-02-19 10:05:27优秀写手
日期:2013-12-18 09:29:09ITPUB社区千里马徽章
日期:2013-06-09 10:15:34ITPUB年度最佳版主
日期:2013-01-30 17:30:25版主9段
日期:2012-07-03 02:21:03
14#
 楼主| 发表于 2006-5-27 21:52 | 只看该作者
public static void Main()
{
Dad d = new Dad();
Mom m = new Mom();
Daughter g = new Daughter();
//以下两个为衍于基类的类
Console.WriteLine(CallAdvice(d));
Console.WriteLine(CallAdvice(m));
//以下为未衍于基类的类,如果调用将出错。
//Console.WriteLine(CallAdvice(g));
}
}
}


代理 二
1〉事件

上一章讲解了有关代理的基本应用,本章将继续讲解深入代理的使用。这里我们讲解使用代理来处理事件。关于事件在另一章进行详细讲解。处理事件在c#中对比c++和vb来说更聪明,你可以写代理然后写事件处理者,事件处理者是一种定义在控件和窗体类中的重载的公共事件。我们在以下的例子中将看到代理在事件中的应用。

使用道具 举报

回复
论坛徽章:
456
ITPUB年度最佳版主
日期:2011-12-28 15:24:18马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14ITPUB年度最佳版主
日期:2014-02-19 10:05:27优秀写手
日期:2013-12-18 09:29:09ITPUB社区千里马徽章
日期:2013-06-09 10:15:34ITPUB年度最佳版主
日期:2013-01-30 17:30:25版主9段
日期:2012-07-03 02:21:03
15#
 楼主| 发表于 2006-5-27 21:52 | 只看该作者
1。写代理
我想处理鼠标单击事件和在鼠标单击左键或右键处理一些代码。写下面的代码在你的初始控件函数中。

this.MouseDown += new System.WinForms.MouseEventHandler(this.Form_MouseDown);

2. 写事件
现在你可以写事件处理,你的事件的输出参数将返回窗体的鼠标事件参数的详细内容。以下时鼠标事件参数成员

MouseEventArgs members

Button 指示哪一个键被压,分为左、右、中、无 。
Clicks 指示鼠标压下次数及释放状态。
Delta 指示鼠标转动数量计数
X 鼠标点击x坐标点
Y 鼠标点击y坐标点

Event Handler

private void Form_MouseDown(object sender, System.WinForms.MouseEventArgs e)
{
switch (e.Button)
{
case MouseButtons.Left:
MessageBox.Show(this,"Left Button Click";
break;
case MouseButtons.Right:
MessageBox.Show(this,"Right Button Click" );
break;
case MouseButtons.Middle:
break;
default:
break;
}

}

使用道具 举报

回复
论坛徽章:
456
ITPUB年度最佳版主
日期:2011-12-28 15:24:18马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14ITPUB年度最佳版主
日期:2014-02-19 10:05:27优秀写手
日期:2013-12-18 09:29:09ITPUB社区千里马徽章
日期:2013-06-09 10:15:34ITPUB年度最佳版主
日期:2013-01-30 17:30:25版主9段
日期:2012-07-03 02:21:03
16#
 楼主| 发表于 2006-5-27 21:53 | 只看该作者
在你的WinForm中测试你的程序,你会看到通过代理事件被关联了。



!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class I
{
public I(){}
~I() {}
public void IDoLoveYou()
{System.Console.WriteLine("I do love You";}

public void why(){System.Console.WriteLine("why?";}
}

class HER
{
public HER(){}
~HER() {}
public void IDo()
{System.Console.WriteLine("...............";}
public void slient(){System.Console.WriteLine(".........";}
}

class TELEPHONE
{public delegate void heartchat();
public TELEPHONE(){}
~TELEPHONE(){}
public void hello(){System.Console.WriteLine("yesterday night,i telephone to my girlfriend"; }

}

class chat{
static void Main() {
I i=new I();
HER her=new HER();
TELEPHONE telephone =new TELEPHONE();
telephone.hello();

TELEPHONE.heartchat tell=new TELEPHONE.heartchat(i.IDoLoveYou);
tell();


TELEPHONE.heartchat answer=new TELEPHONE.heartchat(her.IDo);
answer();

TELEPHONE.heartchat ask=new TELEPHONE.heartchat(i.why);
ask();

TELEPHONE.heartchat noanswer=new TELEPHONE.heartchat(her.slient);
noanswer();


}
}

使用道具 举报

回复
论坛徽章:
456
ITPUB年度最佳版主
日期:2011-12-28 15:24:18马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14ITPUB年度最佳版主
日期:2014-02-19 10:05:27优秀写手
日期:2013-12-18 09:29:09ITPUB社区千里马徽章
日期:2013-06-09 10:15:34ITPUB年度最佳版主
日期:2013-01-30 17:30:25版主9段
日期:2012-07-03 02:21:03
17#
 楼主| 发表于 2006-5-27 21:54 | 只看该作者
如同java一样,在c#中写一个多线程应用是非常简单的,本章将介绍如何在c#种开发多线程程序。在.net中线程是由System.Threading 名字空间所定义的。所以你必须包含这个名字空间。
using System.Threading;

开始一个线程

System.Threading 名字空间的线程类描述了一个线程对象,通过使用类对象,你可以创建、删除、停止及恢复一个线程。创建一个新线程通过new 操作,并可以通过start()方法启动线程

thread = new Thread(new ThreadStart(HelloWorld));
thread.Start();

注意:和java程序不同,创建新线程并调用start()方法后并不去调用run()方法,而是传递线程调用程序

下面是启动线程执行的函数

protected void HelloWorld()
{
string str ;
Console.write("helloworld";
}
}

使用道具 举报

回复
论坛徽章:
456
ITPUB年度最佳版主
日期:2011-12-28 15:24:18马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14ITPUB年度最佳版主
日期:2014-02-19 10:05:27优秀写手
日期:2013-12-18 09:29:09ITPUB社区千里马徽章
日期:2013-06-09 10:15:34ITPUB年度最佳版主
日期:2013-01-30 17:30:25版主9段
日期:2012-07-03 02:21:03
18#
 楼主| 发表于 2006-5-27 21:55 | 只看该作者
杀死一个线程

线程类的 Abort()方法可以永久的杀死一个线程。在杀死一个线程起前应该判断线程是否在生存期间。

if ( thread.IsAlive )
{
thread.Abort();
}

停止一个线程

Thread.Sleep 方法能够在一个固定周期类停止一个线程

thread.Sleep();

设定线程优先级

线程类中的ThreadPriority 属性是用来设定一个ThreadPriority的优先级别。线程优先级别包括Normal, AboveNormal, BelowNormal, Highest, and Lowest几种。


thread.Priority = ThreadPriority.Highest;

使用道具 举报

回复
论坛徽章:
456
ITPUB年度最佳版主
日期:2011-12-28 15:24:18马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14ITPUB年度最佳版主
日期:2014-02-19 10:05:27优秀写手
日期:2013-12-18 09:29:09ITPUB社区千里马徽章
日期:2013-06-09 10:15:34ITPUB年度最佳版主
日期:2013-01-30 17:30:25版主9段
日期:2012-07-03 02:21:03
19#
 楼主| 发表于 2006-5-27 21:55 | 只看该作者
挂起一个线程

调用线程类的Suspend()方法将挂起一个线程直到使用Resume()方法唤起她。在挂起一个线程起前应该判断线程是否在活动期间。

if (thread.ThreadState = ThreadState.Running )
{
thread.Suspend();
}

唤起一个线程

通过使用Resume()方法可以唤起一个被挂起线程。在挂起一个线程起前应该判断线程是否在挂起期间,如果
线程未被挂起则方法不起作用。


if (thread.ThreadState = ThreadState.Suspended )
{
thread.Resume();
}

使用道具 举报

回复
论坛徽章:
2
2009日食纪念
日期:2009-07-22 09:30:002010新春纪念徽章
日期:2010-01-04 08:33:08
20#
发表于 2009-11-16 22:06 | 只看该作者
Reflection,中文翻译为反射。
        这是.Net中获取运行时类型信息的方式,.Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型 (class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,例如:

        Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。
Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。
MethodInfo包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。
诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。

2、命名空间与装配件的关系
        很多人对这个概念可能还是很不清晰,对于合格的.Net程序员,有必要对这点进行澄清。
        命名空间类似与Java的包,但又不完全等同,因为Java的包必须按照目录结构来放置,命名空间则不需要。

        装配件是.Net应用程序执行的最小单位,编译出来的.dll、.exe都是装配件。

        装配件和命名空间的关系不是一一对应,也不互相包含,一个装配件里面可以有多个命名空间,一个命名空间也可以在多个装配件中存在,这样说可能有点模糊,举个例子:
装配件A:
namespace   N1
{
      public   class   AC1   {…}
      public   class   AC2   {…}
}
namespace   N2
{
      public   class   AC3   {…}
      public   class   AC4{…}
}
装配件B:
namespace   N1
{
      public   class   BC1   {…}
      public   class   BC2   {…}
}
namespace   N2
{
      public   class   BC3   {…}
      public   class   BC4{…}
}

        这两个装配件中都有N1和N2两个命名空间,而且各声明了两个类,这样是完全可以的,然后我们在一个应用程序中引用装配件A,那么在这个应用程序中,我们能看到N1下面的类为AC1和AC2,N2下面的类为AC3和AC4。
        接着我们去掉对A的引用,加上对B的引用,那么我们在这个应用程序下能看到的N1下面的类变成了BC1和BC2,N2下面也一样。
        如果我们同时引用这两个装配件,那么N1下面我们就能看到四个类:AC1、AC2、BC1和BC2。

        到这里,我们可以清楚一个概念了,命名空间只是说明一个类型是那个族的,比如有人是汉族、有人是回族;而装配件表明一个类型住在哪里,比如有人住在北京、有人住在上海;那么北京有汉族人,也有回族人,上海有汉族人,也有回族人,这是不矛盾的。

        上面我们说了,装配件是一个类型居住的地方,那么在一个程序中要使用一个类,就必须告诉编译器这个类住在哪儿,编译器才能找到它,也就是说必须引用该装配件。
        那么如果在编写程序的时候,也许不确定这个类在哪里,仅仅只是知道它的名称,就不能使用了吗?答案是可以,这就是反射了,就是在程序运行的时候提供该类型的地址,而去找到它。
有兴趣的话,接着往下看吧。

3、运行期得到类型信息有什么用
        有人也许疑问,既然在开发时就能够写好代码,干嘛还放到运行期去做,不光繁琐,而且效率也受影响。
这就是个见仁见智的问题了,就跟早绑定和晚绑定一样,应用到不同的场合。有的人反对晚绑定,理由是损耗效率,但是很多人在享受虚函数带来的好处的时侯还没有意识到他已经用上了晚绑定。这个问题说开去,不是三言两语能讲清楚的,所以就点到为止了。
        我的看法是,晚绑定能够带来很多设计上的便利,合适的使用能够大大提高程序的复用性和灵活性,但是任何东西都有两面性,使用的时侯,需要再三衡量。

接着说,运行期得到类型信息到底有什么用呢?
还是举个例子来说明,很多软件开发者喜欢在自己的软件中留下一些接口,其他人可以编写一些插件来扩充软件的功能,比如我有一个媒体播放器,我希望以后可以很方便的扩展识别的格式,那么我声明一个接口:
public   interface   IMediaFormat
{
string   Extension   {get;}
Decoder   GetDecoder();
}
这个接口中包含一个Extension属性,这个属性返回支持的扩展名,另一个方法返回一个解码器的对象(这里我假设了一个Decoder的类,这个类提供把文件流解码的功能,扩展插件可以派生之),通过解码器对象我就可以解释文件流。
那么我规定所有的解码插件都必须派生一个解码器,并且实现这个接口,在GetDecoder方法中返回解码器对象,并且将其类型的名称配置到我的配置文件里面。
这样的话,我就不需要在开发播放器的时侯知道将来扩展的格式的类型,只需要从配置文件中获取现在所有解码器的类型名称,而动态的创建媒体格式的对象,将其转换为IMediaFormat接口来使用。

这就是一个反射的典型应用。


4、如何使用反射获取类型
        首先我们来看如何获得类型信息。
        获得类型信息有两种方法,一种是得到实例对象
        这个时侯我仅仅是得到这个实例对象,得到的方式也许是一个object的引用,也许是一个接口的引用,但是我并不知道它的确切类型,我需要了解,那么就可以通过调用System.Object上声明的方法GetType来获取实例对象的类型对象,比如在某个方法内,我需要判断传递进来的参数是否实现了某个接口,如果实现了,则调用该接口的一个方法:

public   void   Process(   object   processObj   )
{
Type   t   =   processsObj.GetType();
if(   t.GetInterface(“ITest”)   !=null   )
                    …
}

        另外一种获取类型的方法是通过Type.GetType以及Assembly.GetType方法,如:
              Type   t   =   Type.GetType(“System.String”);
        需要注意的是,前面我们讲到了命名空间和装配件的关系,要查找一个类,必须指定它所在的装配件,或者在已经获得的Assembly实例上面调用GetType。
        本装配件中类型可以只写类型名称,另一个例外是mscorlib.dll,这个装配件中声明的类型也可以省略装配件名称(.Net装配件编译的时候,默认都引用了mscorlib.dll,除非在编译的时候明确指定不引用它),比如:
          System.String是在mscorlib.dll中声明的,上面的Type   t   =   Type.GetType(“System.String”)是正确的
          System.Data.DataTable是在System.Data.dll中声明的,那么:
Type.GetType(“System.Data.DataTable”)就只能得到空引用。
          必须:
Type   t   =   Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0,   Culture=neutral,   PublicKeyToken=b77a5c561934e089");
          这样才可以,大家可以看下面这个帖子:
                http://expert.csdn.net/Expert/to ... 2.xml?temp=.1919977
          qqchen的回答很精彩


5、如何根据类型来动态创建对象
        System.Activator提供了方法来根据类型动态创建对象,比如创建一个DataTable:

Type   t   =   Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0,   Culture=neutral,   PublicKeyToken=b77a5c561934e089");

DataTable   table   =   (DataTable)Activator.CreateInstance(t);

    例二:根据有参数的构造器创建对象
namespace   TestSpace
{
  public   class   TestClass
      {
      private   string   _value;
       public   TestClass(string   value)  
     {
       _value=value;
       }
  }
}

Type   t   =   Type.GetType(“TestSpace.TestClass”);
Object[]   constructParms   =   new   object[]   {“hello”};   //构造器参数
TestClass   obj   =   (TestClass)Activator.CreateInstance(t,constructParms);

把参数按照顺序放入一个Object数组中即可

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表