这一篇主要介绍委托的一些内部结构,想要了解委托的使用和功能可以看前一篇文章:.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
{
}

继续阅读

0

过年后就一直没写学习笔记了,书第一边已经看完了,后面从事件开始的章节有些复杂,牵扯的知识也很 多。而且最近工作也很忙,所以没有时间来写。这段时间感觉自己对委托又有了一定的认识,所以打算来聊聊 .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. 任何与委托的签名相同的方法,都可以绑定到他上面。(具 体怎么绑定后面介绍)

继续阅读

0

昨天写完了,然后点发表,竟然什么都没了,真是惆怅啊。难道是长时间没响应?之前好象不会把今天重写把。

最近因为在公司因为搞性能测试的没什么人了,我也就逐渐转向性能测试方面的学习了。学习了大概有3个星期了,也用了LR跑了一些场景,不过觉得首先还是要把一些基本概念理解清楚,所以就把一些基本的东西写下来。让自己加深理解。也希望帮助大家了解一些。

 

 

一. 软件性能测试

 

在我们学习性能测试之前,首先要明白什么是性能。汽车有他的性能,比如速度,加速时间,稳定性;电脑硬件有他的性能,比如CPU的频率,处理的速度,游戏的性能。而计算机软件也有他的性能,比如软件运行速度如何,系统稳定性如何等等。性能的好坏不能凭空想象。必须有一些数据来说明来比较。所以我们软件性能测试就是通过得到软件在各种运行情况下的数据来进行分析,来判断软件的性能。一个软件对于不同的人群,他所关注的性能方面是不一样的。比如对于用户来说,他关心的是程序响应的时间,也就是他点一个提交按钮,多长时间可以得到结果。而对于系统管理员他关注的可能是软件在运行时,对系统资源的使用情况,在大量用户使用时的表现如何,能否长时间稳定的工作;而对于开发人员,他们更关心的是系统结构是否合理,SQL执行速度是否够快,有没有内存泄漏等情况。而对于我们测试人员来说,我们需要站在多个 角度来关心性能问题。

 

 

二 性能测试主要术语

 

1:响应时间:

 

响应时间的定义是:对请求作出响应所需要的时间。我们一般把响应时间作为用户角度衡量软件性能的主要指标。

毕竟系统是给用户使用的,用户对系统性能是否满意是用户说了算的。一般情况下响应时间是分为多个步骤的,首先从客户端发出请求,经过网络达到服务器N1,应用服务器处处理S1,访问数据库服务器N2,数据库服务器处理时间为D1,然后返回给应用服务器的网络时间为N3,应用服务器处理时间S2,在传个客户端的网络时间是N4。那么整个响应时间应该为T=N1+S1+N2+D1+N3+S2+N4,当然如果还用到其他服务器,还要加上其他时间。而实际上,除开这T,还有一个客户端的显示时间也要可以算做响应时间。所以时间Tx = T +Ts。但实际上Ts很大程度上是由用户的机器决定的,所以我们一般只关注T,所以通常把T称做响应时间。

一般一个网站,被普遍接受的响应时间是2/5/10,就是说2秒内给用户响应是很满意的,5秒是可以接受,而我一般是等不到10秒就会ALT+F4了!但不同的软件,响应时间的标准要根据实际情况来定。比如一个数据库备分软件,你能要求他5秒内搞定一个1G的数据库吗?

 

继续阅读

0

工作也快1年了,却一直没有写过一篇关于测试方面的文章。一直做功能测试,功能测试这个东西,也有他的一套理论,一套流程,以及测试过程中的一些方法,什么边界法,等价类。但实际工作中,因为真正把测试流程走的很好的公司毕竟很少。所以编写测试计划,写完整的测试用列,运用这些方法可能机会不多。而实际工作中,完全的功能测试重要的就是理解业务和需求。所以具体的什么流程就不说了,网上资料很多。

 

下面谈谈自己对功能测试的一点看法:

 

需求理解了,知道客户想要系统实现什么,理解了业务,就知道了系统是怎样一个流程来实现的。然后按照需求来进行测试的,不满足需求要求的都可以认为是BUG。但实际中,这样一个简化了过程都很难,毕竟想从开发那拿到一份完整详细的需求都是很不容易的(当然,可能也有比较规范的公司,但目前大多数应该是这个情况)。

 

当然功能测试也不是真的那么简单,要做好一个功能测试,前提是要对需求比较熟悉,各个业务细节都很了解。甚至做到比开发人员还要了解。这或许是测试人员唯一的优势了。个人做了快1年功能测试的一点看法。要做好功能测试,还需要对整个业务中数据库的操作比较清楚(针对信息管理相关的系统)。比如哪个业务需要用到那些表,做怎么样的操作。了解了这个就可以不单单从程序前台来看程序,看到数据库的过程,更有利于你找到隐藏的BUG。比如库表没有进行关联删除,日志表没有插如记录。这些是从前台看不出来的,但实际可能会导致程序出现问题。

继续阅读

0

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

一 字符

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

0

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

 

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类型,这是一个委托类型!什么是委托类型?

继续阅读

0

好久没有写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); 
} 

继续阅读

0

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

 

一 类型成员介绍

 

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

 

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

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

继续阅读

0

四 装箱与拆箱

 

前面主要都讨论的是同类型直接的转换,引用到引用,值类型到值类型。还有一种用的非常多的就是引用类型和值类型之间的转换,比如传递参数时,值类型存储到一个引用类型时。也就是经常可以听到的装箱和拆箱操作。这确实是个非常复杂的地方。因为引用类型和值类型的内存空间是不同的,也就导致了许多性能问题和拷贝使用等问题。对于每一种值类型,运行库都提供一种相应的已装箱类型,这是与值类型有着相同状态和行为的类。当需要已装箱的类型时,某些语言要求使用特殊的语法(如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进行装箱操作。
   }
 }
}

继续阅读

0

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

 

一 类型基础

 

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

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

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

 

继续阅读

0