半年没有写东西了。也就出差了半年。半年没有用C#,写了半年VC,呵呵。有时候其实有挺多东西写的,不过一忙起来人就懒了。简单的东西不想写,复杂的又写不了,哈哈。最近不是太忙,大概看了下COM组件模型,然后对DLL工作,库文件有了一些兴趣。因为工作和自己写的程序可以延伸到这些知识上,所以对DLL进行了一定的了解,而且对于直接开始编写C#应用程序的人来说,也很少会去了解这些,所以决定写下来。

 

 

 一 库文件

 

 

库文件是我们在接触编程时经常听到的词。那么什么是库文件。其实库文件是一种重用的思想。比如我们自己编写C#的程序,可能会把公用的一些方法放在一个名为Common的项目中,然后编译成DLL,其他项目引用这个程序集,就可以调用这个里面的方法,而不用自己去实现。在说的大一点,.NET中提供给我们使用的类,也是存放在.NET库中的。而整个WINDOWS系统,都是建立在库文件基础上的。

实在最初的时候是没有库文件的概念,所有功能都是自己实现的。为了提高效率,减少重复工作,就必须对代码重用。重用方法有很对,比如对于一些通用的方法的实现代码让编译器自己生成,但这个问题是,一旦方法变更会添加,编译器也必须修改了。另一个方法是把常用的方法编译成.obj模块文件。这样在编译的时候,去链接这些模块文件,就能实现代码重用。但是所有方法放到一个obj文件中,文件会很庞大,占用内存;如果为每个方法提供一个obj文件,那又会相当的麻烦。

于是就出现了静态库(static library),静态库是一个或多个.obj文件的集合。使用到这些.obj文件对应的函数时,只需要在连接时提供该静态库,而不需要列举用到的.obj文件。而连接器进行连接的时候,只会将程序中用到的函数对应的.obj文件连接到程序中。静态库的形式就是我们WINDOWS上常见的.lib文件。但静态库的确定是,每个程序使用时都会吧需要的obj文件拷贝到内存中,100个程序就有100个拷贝,这样对内存的浪费很大,而且如果静态库文件更新的话,程序也需要重新编译,进行连接。于是共享库(shared library,也叫做动态连接库)就出现了。首先他是被加载到公用的内存空间中,是所有程序共享的,所以对节省了内存;另外他在编译时没有象静态库那样,把代码直接连接到了程序中,只是插入了动态库的一些信息,供调用时使用。这样,我们就有可能直接修改动态库,而不需要重新编译程序。

动态库当然也有他的问题,比如DLL HELL。DLL Hell 是指当多个应用程序共享一个DLL或COM组件时所引发的一系列问题。比如一个应用程序安装一个新版本DLL,而该DLL与机器上的现有版本不向后兼容。这样就可能导致以前的引用程序引发异常。而.NET的强命名程序集就解决了这个问题,它通过程序集(DLL)名称、语言、版本、KEY来区分DLL,而不仅仅是只通过名字。也就能保证对个版本的DLL同时工作。

 

继续阅读

注意:在写完文章后很久才发现自己文章中【编译】两个字的让人误解,比如方法槽偏移量是在编译时获得的,其实我想表达的是JIT编译,而不是指IL编译。我大概修改了一些关键地方,但是可能有很多遗漏。大家要自己判断了,哈!

封装、继承、多态是面向对象的最重要的3个特点。但是想真的弄明白他们其中的奥秘还是的费一番功夫。记得在学校学习C++的时候,讲到这个地方,自己早已是一头雾水,当时还在想,弄成private做什么,多麻烦啊。到了多态,继承更是昏死了。今天就来深入了解下其中的奥秘吧。本文主要是从内存结构出发来讲解.NET中的继承和多态,因为内存布局的不同所以和其他语言中的继承多态可能有一定区别。

 

 

一 笔试题目

 

 class Program
    {
        static void Main(string[] args)
        {
            Cpu c1 = new Cpu();
            c1.fun();
            Cpu c2 = new IntelCpu();
            c2.fun();
            Cpu c3 = new CoreCpu();
            c3.fun();
            IntelCpu  c4 = new CoreCpu();
            c4.fun();
        }
    }
    class Cpu
    {   
        public Cpu()
        {
            Console.WriteLine("初始化Cpu");
        }
        public virtual void fun()
        {
            Console.WriteLine("Cpu的方法/n");
        }
    }
    class IntelCpu : Cpu
    {
        public IntelCpu()
        {
            Console.WriteLine("初始化IntelCpu");
        }
        public override void fun()
        {
            Console.WriteLine("IntelCpu的方法/n");
        }
    }
    class CoreCpu : IntelCpu
    {
        public CoreCpu()
        {
            Console.WriteLine("初始化CoreCpu");
        }
        public new void fun()
        {
            Console.WriteLine("CoreCpu的方法/n");
        }
    }

上面是我们常见的关于继承和多态的题目。或许很多人都有一套做这种题目的方法,能够让你准确的得到答案,但是我们了解继承和多态不是为了背公式,不是为了做题目,是未来灵活使用。所以有必要弄清楚她内部到底是怎么实现的。或许平时可能用不上,但是我认为还是会有所帮助的。

继续阅读

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

 

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

继续阅读

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

 

一 类型基础

 

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

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

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

 

继续阅读