这一篇主要介绍委托的一些内部结构,想要了解委托的使用和功能可以看前一篇文章:.NET学习笔记(八) ——委托(上)

前天不小心感冒了,吃了药但还是晕晕的,还是继续写把。。。前面介绍了委托的功能和使用方法。委托实际是对一个函数指针的封装,那么他是如何指向一个函数,有是如何把多个方法都绑定起来的呢?

 

一 委托的内部结构

 

下面是简单的一个定义委托方法,写起来很简单,当编译器编译这句话的时候做了什么呢?

//申明一个委托要绑定的方法签名
public deletgate void ExampleDeletgate(int x);

通过ILDASM我们可以看到,系统产生了以下代码:

//构造器有2个参数为了方便后面使用,我重新定义这2个变量名字
//public ExamplDelegate(object target,int methodPtr)
.method public hidebysig specialname rtspecialname  
       instance void  .ctor(object 'object', native int 'method') runtime managed
{
}

//下面两个是委托的一个异步回调用方法,我们暂时不关注他们
.method public hidebysig newslot virtual 
        instance class [mscorlib]System.IAsyncResult 
        BeginInvoke(int32 x,class [mscorlib]System.AsyncCallback callback,object 'object') runtime managed
{
}

.method public hidebysig newslot virtual 
        instance void  EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
{
}

//这个方法和委托指定的方法原形是一样的,我同样改写下
//public void virtual Invoke(int32 x);
.method public hidebysig virtual instance void Invoke(int32 x) runtime managed
{
}

继续阅读

过年后就一直没写学习笔记了,书第一边已经看完了,后面从事件开始的章节有些复杂,牵扯的知识也很 多。而且最近工作也很忙,所以没有时间来写。这段时间感觉自己对委托又有了一定的认识,所以打算来聊聊 .net里的委托。

 

一 什么是委托

 

MSDN中给出的定义:

委托是用来处理其他语言(如 C++、Pascal 和 Modula)需用函数指针来处理的情况的。不过与 C++ 函数 指针不同,委托是完全面对对象的;另外,C++ 指针仅指向成员函数,而委托同时封装了对象实例和方法。

简单的说委托就是对函数指针的一个封装。所谓的函数指针,了解C++的人都应该知道,函数指针中存放的 是函数的地址,当调用是,使用这个指针就可以调用到函数。而委托只不过是给这个指针穿的件漂亮的衣服, 使他变的更安全更强大。

delegate 声明定义一种引用类型,该类型可用于将方法用特定的签名封装。委托实例 封装静态方法或实例方法。委托大致类似于 C++ 中的函数指针;但是,委托是类型安全和可靠的。

delegate  void  DeletgateEx (int x);  //声名一个委托

DeletgateEx dx =new dx(print);   //实例化一个委托并绑定一个方法  

void print (int x)
{
  Console.WriteLine(x.ToString());
}

delegate 是声明委托的关键字

  1. 定义一个委托类型,这看起来有点奇怪,和一般的定义不一样?好象是在声明一个方法。要注意,委托 是对函数指针的封装,所以你就把委托看成一个存放函数的对象。但是委托不是任何函数都可以存放,他只能 存放和他声明的函数拥有相同签名的函数。从例子可以看出,这个委托只能存放一个没有返回值,有一个int 形参数的方法。
  2. 实例化这个委托,和其他引用对象一样,使用new创建。它需要一个参数,那就是要与此委托绑定的方法。
  3. 任何与委托的签名相同的方法,都可以绑定到他上面。(具 体怎么绑定后面介绍)

继续阅读

和往常一样,开篇还是介绍下最近情况了。今天是农历12月24,我们那边今天是过小年。总算是进了年关了,也给大家摆个早年了。不过最近火车成了大问题,能不能顺利回家还是个问题。自己也没啥心情看书了。哎~~还是不能堕落了。而且住的附近无线网用不了了,很久没有写了。书到是看到最后几章了。不过越到后面就越觉得有些复杂了。特别是有些地方以前很少接触用的也少,比如特性 ,枚举,字符的本地化这些。而且目前有好多笔记没写。所以决定用的不多的和很复杂的地方暂时就不去深研了。毕竟是第一轮学习。所以就把实际用的比较多的拿出来写下。其他那些就大概的照本宣科好了。

一 字符

(今天来做个标记,免得说好长时间没写了,哈哈~~)

事件其实也是属于类型设计里的内容,不过因为他比较重要,也比较难理解,我就把他单独拿出来学习。

 

1 .下面是一个我们在程序中最常见的代码

 

private void button1_Click(object sender, System.EventArgs e)
 {
          //按妞被点击后执行的操作;    
 }

他的意思是当你点击一个按钮时,他就会执行这个方法里的代码,产生相应的操作。这个时候我们就可以说‘单击’button1这个事件发生的时候,他会自动去执行这个方法。这看起来很简单。点一个按钮,然后执行代码。这在这种基于驱动的程序中很常见。但有个问题不知道大家有没有想过。

这段代码写在那?一般是写在一个from类里,我点这个按钮属于button类。我实际实在button对象里调用了form对象里的方法。那为什么在点按钮的时候他会执行这个方法呢?

说简单点,就是其实就是在一个对象在执行一个方法时调用其他对象的方法。按事件来说就是一个对象的某个事件被触发时,通知其他对象,其他对象执行相应的一些操作。这里就是button的click事件触发后,通知form对象,执行button1_click()方法。那么当事件触发后是如何通知其他对象的呢?

// button1
// 登记方法到button对象
this.button1.Click += new System.EventHandler(this.button1_Click);

在程序中可以看到button1在设置时有这样一句话,他的基本意思就是把button1_click()方法登记到button1.Click对事件象上,这样当触发click事件时就会调用button1_click()方法。也就达到了通知的目的。其中button1.Click又是一个EventHandler类型,这是一个委托类型!什么是委托类型?

继续阅读

好久没有写BLOG了,BLOG一直有点问题。最近一段时间也有点堕落,书看的不多,上个月底 一直在看关于 类之间的继承,多态 。虚方法的继承,隐藏,重写,方法表,内存结构等。还在CSDN上看了不少帖子。这些东西有空还是会总结一下的。

新年了,希望有新的气象。有好多事都会有大的变化。目标,计划都有了,需要的就是自己不断的坚持,好好努力,按自己的路线走下 去。也祝大家新年快乐把。

———————————————————————————————————————————–

(接上篇)

疑问:基元类型为什么不和Decimal一样提供ToXXX()方法呢?他内部是否实现了这些方法?

解答:通过用Reflector,我看了下他们

 

1. Int32里是类似下面的方法,可以发现实际是调用了Convert.ToInt16里的实现 并且是受保护的方法。内部也没有转换操作符 。
short   IConvertible.ToInt16 (IFormatProvider   provider) 
{ 
        return   Convert.ToInt16(this.m_value); 
} 
2. decimal里面也与这样的受保护的实现方法
short   IConvertible.ToInt16 (IFormatProvider   provider) 
{ 
        return   Convert.ToInt16(this); 
} 

继续阅读

这段时间工作有点忙,系统刚上线,也有点累。这段时间主要看到了书中.net类型设计这一部分,这一部分主要介绍的是如何用不同的成员来设计一个类型。

 

一 类型成员介绍

 

面向对象的语言中,最重要的一个特点就是封装,说到最多的一个词就是类。什么是类,类是定义同一类所有对象的变量和方法的蓝图或原型。让数据同操作分离开。人类是一个类,而我们每个人就是这个类的一个实例,也就这个类的一个对象。 我们这里说的类型,并不是程序中的类Class,因为我们知道了类型有,值类型,引用类型。这里用类Class主要是帮助大家理解,毕竟它是用的最多。一个类型,他可以包括以下一个或多个成员:

 

  • 常数:常数是一个表示恒定不变的数值符号。常数 总是和类型而非他们实例相关联,所以他们可以说总是静态的。
  • 字段:字段表示一个数据的值,他可以是只读的,也可以是可读写的。字段分为动态字段和实例字段。一般字段声名为私有,这也是面向对象中推荐的作法,防止字段被随意操作。也就是我们类中定义的数据成员。
  • 方法:方法是一个函数,用来改变或查询一个类型,或者一个对象的状态。也就是我们类中定义的成员函数。
  • 属性:属性也是一种方法,当他比较特殊,他主要是用来设置和保护类中的数据成员。
  • 事件:用通俗的话来说,就是你操作某个对象时,执行的某一个方法。他只在特定的时间,由指定的对象来执行指定的方法。

除了上面介绍的这些,一个类型中还包括,构造器(类型初始化用),重载操作符,转换操作符等。对于一个类型,内部可以嵌套定义其他类型。这可以使得复杂的类型划分为小的代码块,简化实现。下面是类型成员的限定修符的解释:

继续阅读

四 装箱与拆箱

 

前面主要都讨论的是同类型直接的转换,引用到引用,值类型到值类型。还有一种用的非常多的就是引用类型和值类型之间的转换,比如传递参数时,值类型存储到一个引用类型时。也就是经常可以听到的装箱和拆箱操作。这确实是个非常复杂的地方。因为引用类型和值类型的内存空间是不同的,也就导致了许多性能问题和拷贝使用等问题。对于每一种值类型,运行库都提供一种相应的已装箱类型,这是与值类型有着相同状态和行为的类。当需要已装箱的类型时,某些语言要求使用特殊的语法(如C++要用关键字);而另外一些语言会自动使用已装箱的类型(C#是自动的)。在定义值类型时,需要同时定义已装箱和未装箱的类型。

  1. 由前面我们可以知道,值类型是分配在线程的堆栈上,而引用类型是分配在托管堆上的。所谓的‘装箱’也就是把值类型转化为一个引用类型的过程。实际上也就是把分配在堆栈上的对象,装箱(可能说打包比较形象,前面说过分配在托管堆的对象回又个附加成员),然后重新分配到托管堆上的。装箱操作通常由以下几步组成:
    在托管堆上为新生成的引用类型分配内存空间。这个空间大小为值类型本身大小和附加成员(方法表指针和SyncBlockIndex)
  2. 将值类型实例的字段拷贝到托管堆上新分配对象的内存中。
  3. 返回托管堆中新分配对象的地址。这个地址就是一个指向对象的引用。值类型实例也就变成了一个引用类型对象。
//声明一个值类型
struct Point
{
  public Int32 x,y;
}


class app
{
 static void Main()
 {
   ArrayList a = new ArraryList();
   Point p ;            //值类型分配到线程堆栈上
   for(Int32 i = 0; i < 10 ;i++)
   {
      p.x = p.y = 1;    //初始化值类型成员
      a.Add(p);         //Add(Object obj)方法要接受一个引用类型,所以会对p进行装箱操作。
   }
 }
}

继续阅读

这段时间在学习的过程中,也看了其他不少人写的读书笔记,感觉每个地方都有好多东西可以写很多内容。但鉴于目前自己是在第一次学习阶段,很多地方无法弄的太深。此笔记也主要是对每一块内容学习的一个总结,每次在写笔记时,我觉得自己都会有新的收获,了解的更清楚。希望随着学习的深入也能写一些有深度的东西。最近这几天晚上上不了网,而且太累,导致耳鸣了一两天,所以今天才写笔记。以后每天还是早点睡觉,身体是革命的本钱啊!

 

一 类型基础

 

在.net里,FCL中定义了很多的类型,CLR的要求是每个类型都要继承自System.Object这个类型。在我们定义一个类行的时候,往往是隐式继承于Object的。Object这个类型定义了四个公有的实例方法和两个受保护的方法,而系统中所有类型都能使用这些通用的方法。

  • Equals: 此方法是判断两个对象的值是否相同的。在Object中的实现是判断两个对象是否指向同一个对象。而在派生类中,主要用于判断值是否相等。其中引用类型和值类型是不同的。自己定义的类型要判断时需要重写此函数。
  • GetHashCode:这个方法是返回对象的散列码。如果一个对象被用作散列表的一个键值,那么该对象的类型应该重写此方法。
  • Tostring:此方法默认情况下是返回一个类型的全名。另一种常见的用法就是重写该方法让它返回一个表示对象状态的字符串。还可以通过重写他来得到一个表示对象字段值的字符串。
  • GetType:方法返回一个类型为继承自Type的对象实例,标识了该方法所属对象的类型。此方法是一个非虚方法,可以防止派生类重写此方法而隐瞒实际的类型,破坏类型安全。
  • MemberwiseClone:这也是个非虚方法,他是创建一个新的类型实例,并将去字段设置为和this对象的字段相同。最后返回创建实例引用。后面的深拷贝时回用到此方法。
  • Finalize:这是一个虚方法,当垃圾回收齐判定某个对象为可回收的垃圾时,垃圾回收器回在对象被回收前调用此方法。此方法很重要。后面学习中还会具体涉及。

CLR要求每个对象都需要用new来创建,new的话系统会执行一系列的内存等分配工作。但要注意的是CLR中没有提供delete这样一个关键字来手动的释放内存,因为这些都是由垃圾回收器来完成的。也许有人会奇怪,我们平时定义一些简单的数值变量的时候并没有用new,只是在定义类的时候才用。这就引出了后面的话题。.net中的数据类型

 

继续阅读

为了得到一些东西,我们必须放弃一些东西,在每个人的人生天平上,孰重孰轻,只有我们自己知道,但是一旦选择了,我们就要尽量去做好它,保留我们内心中那少少值得骄傲的地方。

                                                                                                                                                                                                        ——————————-学习题记

看到小麟写的很好,就拿过来。大家一起共勉。毕业到工作,有4个月了,突然发现有些不是自己想要的。即便现在的环境和安逸和轻松。谈到.net,或许自己连个菜鸟都算不上。但,为了做自己喜欢的事,从现在起,我努力把自己变为一只菜鸟。《.net框架程序设计》是一本非常好的书,我通过学习此书,顺便做点笔记,尽量用自己的理解。笔记中或许会有许多错误,有许多不正确的认识。也请新人,菜鸟,老鸟,高手们多多指教。

 

一 平台介绍

 

NET Framework 具有两个主要组件:公共语言运行库和 .NET Framework 类库。

公共语言运行库是 .NET Framework 的基础。公共语言运行库管理内存、线程执行、代码执行、代码安全验证、编译以及其他系统服务。这些功能是在公共语言运行库上运行的托管代码所固有的。代码管理的概念是运行库的基本原则。以运行库为目标的代码称为托管代码,而不以运行库为目标的代码称为非托管代码。

.NET Framework 的另一个主要组件是类库,它是一个综合性的面向对象的可重用类型集合,您可以使用它开发多种应用程序,这些应用程序包括传统的命令行或图形用户界面 (GUI) 应用程序,也包括基于 ASP.NET 所提供的最新创新的应用程序(如 Web 窗体和 XML Web services)。

继续阅读