代码改变世界

C#

2010-12-16 22:46  CuiWenKe  阅读(318)  评论(0)    收藏  举报

.NET 基础部分面试题: 

(1)     new有几种用法 

第一种:new Class();
第二种:覆盖方法
public new XXXX(){}
第三种:new 约束指定泛型类声明中的任何类型参数都必须有公共的无参数构造函数。

(2) 如何把一个array复制到arrayList
foreach( object o in array )arrayList.Add(o);
(3) datagrid.datasouse可以连接什么数据源 [dataset,datatable,dataview]
dataset,datatable,dataview , IList
(4) 概述反射和序列化
反射:程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性
序列化:序列化是将对象转换为容易传输的格式的过程。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。在另一端,反序列化将从该流重新构造对象。
(5) 概述o/r mapping 的原理(对象关系映射)
利用反射,配置 将类于数据库表映射,ORM-Object/Relational Mapping。

(6) 类成员有( )种可访问形式

可访问性:public ,protected ,private,internal
(7) sealed修饰的类有什么特点
sealed 修饰符用于防止从所修饰的类派生出其它类。如果一个密封类被指定为其他类的基类,则会发生编译时错误。
密封类不能同时为抽象类。
sealed 修饰符主要用于防止非有意的派生,但是它还能促使某些运行时优化。具体说来,由于密封类永远不会有任何派生类,所以对密封类的实例的虚拟函数成员的调用可以转换为非虚拟调用来处理。
(8) 列举ADO.NET中的五个主要对象,并简单描述
connection,command,dataReader,trans,dataset ...
(9) 执行下面代码后:
String strTemp ="abcdefg 某某某";
Int i System.Text.Encoding.Default.GetBytes(strTemp).Length;
Int j = strTemp.Length;
问:i=(14 ) ;j=(11 )
i=(14 ) ;j=(11 ) 中文两个字节
(10)  C#
中,string str = null string str ="",请尽量用文字说明区别。(要点:说明详细的内存空间分配)
string str =""表示一个空串,被实列化了,占用了内存空间,  null,表示一个空串,没有占用了空间。   
(11) 详述.NETclassstruct的异同!
class:放在 ? struct放在?
struct值传递
类与结构有很多相似之处:结构可以实现接口,并且可以具有与类相同的成员类型。然而,结构在几个重要方面不同于类:结构为值类型而不是引用类型,并且结构不支持继承。结构的值存储在“在堆栈上”或“内联”。细心的程序员有时可以通过聪明地使用结构来增强性能。
(12) 概述.NET里对 remoting webservice 两项技术的理解和实际中的应用。
WebService的特点是: 平台独立性(Platform-independent)、跨语言(只要能支持XML的语言都可以)以及穿透企业防火墙;webservice是基于http的是无状态的;但是它的缺点也很明显,就是需要部署一台Web Server;而且速度比较慢;

.net Remoting的特点是:优点是用户既可以使用TCP信道进行二进制流方式通信,也可以使用HTTP信道进行SOAP格式的通信,效率相对WebService要高不少;remoting可以用于有状态的情况;但是它的缺点也很明显,.net remoting只能应用于MS的.net framework之下。使用场合:如果互动双方都是支持.NET技术的环境,并且在操作系统上能提供一致的验证机制,而且很重视沟通双方作业的效率,就是.NET Remoting上场的时机。相反的,如果沟通双方是异质环境,又或沟通的模式就是无状态的情况,持续进行的互动作业前后是没有关联的,Web Service就是理想选择了。

(13.什么是code-behind技术
aspx and cs , codebehind是指代码和用户界面分开
14.概述三层结构体系
web/business/dataaccess

16.  面向对象的思想主要包括什么?
答: 继承 多态 封装

● 封装:用抽象的数据类型将数据和基于数据的操作封装在一起,数据被保护在抽象数据类型内部。

● 继承:子类拥有父类的所有数据和操作。

● 多态:一个程序中同名的不同方法共存的情况。

有两种形式的多态– 重载与重写。
18. 什么叫应用程序域?什么是受管制的代码?什么是强类型系统?什么是装箱和拆箱?什么是重载?CTSCLSCLR分别作何解释?
答:装箱就是把值类型转成引用类型,从MS IL角度看好像是boxing,没记错的话是把值从堆栈转到堆中.拆箱相反,重载就是指一个方法名同,参数个数不同,返回值可以相同的方法.CLR是通用语言运行时,其它的不清楚.
19.列举一下你所了解的XML技术及其应用
答:XML可是好东西,保存配置,站与站之间的交流,WEB SERVICE都要用它.
(20) 值类型和引用类型的区别?写出C#的样例代码。
答:结构是值类型,类是引用类型,所以传结构就是值类型的应用啦,传对象或类就是引用类型的,这个不用多写了吧.
(21)  如何理解委托?
答: 委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的调用可以像其他任何方法一样,具有参数和返回值,如下面的示例所示:

public delegate int PerformCalculation(int x, int y);

与委托的签名(由返回类型和参数组成)匹配的任何可访问类或结构中的任何方法都可以分配给该委托。方法可以是静态方法,也可以是实例方法。这样就可以通过编程方式来更改方法调用,还可以向现有类中插入新代码。只要知道委托的签名,便可以分配自己的委托方法。

委托具有以下特点:
委托类似于 C++ 函数指针,但它是类型安全的。
委托允许将方法作为参数进行传递。
委托可用于定义回调方法。
委托可以链接在一起;例如,可以对一个事件调用多个方法。
方法不需要与委托签名精确匹配。有关更多信息,请参见协变和逆变。
C# 2.0 版引入了匿名方法的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。

(22)  C#中的接口和类有什么异同。 

接口是负责功能的定义,项目中通过接口来规范类,操作类以及抽象类的概念!
而类是负责功能的具体实现!
在类中也有抽象类的定义,抽象类与接口的区别在于:
抽象类是一个不完全的类,类里面有抽象的方法,属性,也可以有具体的方法和属性,需要进一步的专业化。
但接口是一个行为的规范,里面的所有东西都是抽象的!
一个类只可以继承一个基类也就是父类,但可以实现多个接口
PS:接口除了规范一个行为之外,在具体项目中的实际作用也是十分重要的,在面向对象的设计原则以及设计模式的使用中,无不体现作为一个接口的使用好处,最直接的就是设计原则中OCP(开放封闭原则),我们使用接口,而不需要关心他的具体实现,具体实现的细节变化也无关客户端(使用接口的类)的使用,对与扩展是开放的,我们可以另写一个接口的实现来扩展当前程序,而不影响上层的使用,但对修改是封闭的,即我们不能够再去修改接口的定义,当然这个“不能够”是指在规范原则上不应该这么做! 

(23) UDP连接和TCP连接的异同。 

答:前者只管传,不管数据到不到,无须建立连接.后者保证传输的数据准确,须要连结.

 

(25)  进程和线程分别怎么理解? 

答: 进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的区别在于: 简而言之,一个程序至少有一个进程,一个进程至少有一个线程. 线程的划分尺度小于进程,使得多线程程序的并发性高。 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源. 一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行

(26) .活动目录的作用。 

答: 详细参考网址 http://www.microsoft.com/china/windows2000/guide/server/features/dirlist.mspx
(27) 解释一下UDDIWSDL的意义及其作用。

答: 统一描述、发现和集成协议(UDDI, Universal Description, Discovery and Integration)是一套基于Web的、分布式的、为Web服务提供的信息注册中心的实现标准规范,同时也包含一组使企业能将自身提供的Web服务注册以使得别的企业能够发现的访问协议的实现标准。UDDI 提供了一组基于标准的规范用于描述和发现服务,还提供了一组基于因特网的实现。

(28) 什么是SOAP,有哪些应用。

答:SOAP(Simple Object Access Protocol )简单对象访问协议是在分散或分布式的环境中交换信息并执行远程过程调用的协议,是一个基于XML的协议。使用SOAP,不用考虑任何特定的传输协议(最常用的还是HTTP协议),可以允许任何类型的对象或代码,在任何平台上,以任何一直语言相互通信。这种相互通信采用的是XML格式的消息,具体请看:http://playist.blogchina.com/2521621.html
(29) 如何部署一个ASP.NET页面。

答:随便啦,想直接上传就直接上传,想打包成EXE就打包,看个人喜好.

(30) 如何理解 . NET中的垃圾回收机制。 

答: NET Framework 的垃圾回收器管理应用程序的内存分配和释放。每次您使用 new 运算符创建对象时,运行库都从托管堆为该对象分配内存。只要托管堆中有地址空间可用,运行库就会继续为新对象分配空间。但是,内存不是无限大的。最终,垃圾回收器必须执行回收以释放一些内存。垃圾回收器优化引擎根据正在进行的分配情况确定执行回收的最佳时间。当垃圾回收器执行回收时,它检查托管堆中不再被应用程序使用的对象并执行必要的操作来回收它们占用的内存。

(31) 以下叙述正确的是:

A. 接口中可以有虚方法。     B. 一个类可以实现多个接口。
C. 接口不能被实例化。        D. 接口中可以包含已实现的方法。 (BC)

(32)  从数据库读取记录,你可能用到的方法有

A. ExecuteNonQuery            B. ExecuteScala

C. Fill                              D. ExecuteReader  (BCD)

(34) 一列数的规则如下: 112358132134......

求第30位数是多少, 用递归算法实现。(C#语言)

 public class MainClass
    {


        public static void  Main()  
        {
            Console.WriteLine(Foo(30));
        }
        public static int Foo(int i)
        {
            if (i <= 0)
                return 0;
            else if(i > 0 && i <= 2)
                return 1;
            else return Foo(i -1) + Foo(i - 2);

 }
    }

 

(35)  程序设计: 猫大叫一声,所有的老鼠都开始逃跑,主人被惊醒。(C#语言)

要求: 

1. 要有联动性,老鼠和主人的行为是被动的。

2.考虑可扩展性,猫的叫声可能引起其他联动效应。

要点:1. 联动效果,运行代码只要执行Cat.Cryed()方法。2. 对老鼠和主人进行抽象

评分标准: <1>.构造出Cat、Mouse、Master三个类,并能使程序运行(2分)

            <2>从Mouse和Master中提取抽象(5分)
            <3>联动效应,只要执行Cat.Cryed()就可以使老鼠逃跑,主人惊醒。(3分)

 public interface Observer
    {
        void Response();    //观察者的响应,如是老鼠见到猫的反映
    }
    public interface Subject
    {
        void AimAt(Observer obs);  //针对哪些观察者,这里指猫的要扑捉的对象---老鼠
    }
    public class Mouse : Observer
    {
        private string name;
        public Mouse(string name, Subject subj)
        {          
            this.name = name;
            subj.AimAt(this);
        }
       
        public void Response()
        {
            Console.WriteLine(name + " attempt to escape!");
        }
    }
    public class Master : Observer
    {  
        public Master(Subject subj)
        {          
            subj.AimAt(this);
        }
       
        public void Response()
        {
            Console.WriteLine("Host waken!");
        } 
    }

 public class Cat : Subject

 { private ArrayList observers;
        public Cat()
        {  
            this.observers = new ArrayList();
        }
        public void AimAt(Observer obs)
        {
            this.observers.Add(obs);
        }
        public void Cry()
        {
            Console.WriteLine("Cat cryed!");
            foreach (Observer obs in this.observers)
            {
                obs.Response();
            }
        }
    }
    class MainClass
    {      
        static void Main(string[] args)
        {
            Cat cat = new Cat();
            Mouse mouse1 = new Mouse("mouse1", cat);
            Mouse mouse2 = new Mouse("mouse2", cat);
            Master master = new Master(cat);
            cat.Cry();
        }
    }

(36) C# 的四种排序

冒泡排序

 public void BubbleSort(int [] list)

{  

int i,j,temp;

 bool done=false;

 j=1;

 while((j<list.Length) &&(!done))

 {

   done=true;

    for(i=0;i<list.Length-j;i++)

    {

       if(list[i] > list[i+1]) 

        {

             done=false;

             temp=list[i];

             list[i]=list[i+1];

             list[i+1]=temp;

         } 

     }

      j++;

  }

选者排序

private int min;     

public void SelectionSort(int[] list)

{  

     for(int i=0;i<list.Length-1;i++)

     { 

         min=i;

         for(int j=i+1;j<list.Length;j++)

         {   if(list[j]<list[min])

                   min=j;

         }

         int t=list[min];

         list[min]=list[i];

         list[i]=t;

      }

 }

插入排序

public void InsertionSort(int [] list)

{

   for(int i=1;i<list.Length;i++)

   {

      int t=list[i];

      int j=i;

      while((j>0)&&(list[j-1]>t))

      {

             list[j]=list[j-1];

             --j;

       }

       list[j]=t;

     }

              }

/// <summary>

/// 希尔排序

/// 希尔排序是将组分段,进行插入排序.

/// </summary>

/// <param name="list"></param>

public void ShellSort(int [] list)

{

   int inc;

   for(inc=1;inc<=list.Length/9;inc=3*inc+1);

   for(;inc>0;inc/=3)

   {

        for(int i=inc+1;i<=list.Length;i+=inc)

        {

                int t=list[i-1];

                int j=i;

                while((j>inc)&&(list[j-inc-1]>t))

                 {

                       list[j-1]=list[j-inc-1];

                       j-=inc;

                  }

                 list[j-1]=t;

            }

       }

          }

  (37) 能用foreach遍历访问的对象需要实现(IEnumerable)接口或声明GetEnumerator方法的类型。

   (38) Singleton如何写设计模式

   答: 单件模式的使用意图就是:保证一个类仅有一个实例,并提供一个该实例全局的访问点

 (39)什么是Application Pool

这是微软的一个全新概念:应用程序池是将一个或多个应用程序链接到一个或多个工作进程集合的配置。因为应用程序池中的应用程       序与其他应用程序被工作进程边界分隔,所以某个应用程序池中的应用程序不会受到其他应用程序池中应用程序所产生的问题的影响。

(40)链表和数组的区别,各有什么优缺点.

链表的特性是在中间任意位置添加删除元素的都非常的快,不需要移动其它的元素。 链表顾名思义,要把各个元素链接起来才算撒。 通常链表每一个元素都要保存一个指向下一个元素的指针(单链表)。 双链表的化每个元素即要保存到下一个元素的指针,还要保存一个上一个元素的指针。 循环链表则把最后一个元素中保存下一个元素指针指向第一个元素。 数组是一组具有相同类型和名称的变量的集合。这些变量称为数组的元素,每个数组元素都有一个编号,这个编号叫做下标,我们可以通过下标来区别这些元素。数组元素的个数有时也称之为数组的长度。

数组是一块连续的空间,声明时长度就要确定 链表是一块不连续的动态空间,长度可变 数组的优点是速度快,数据操作直接使用偏移地址, 链表需要按顺序检索节点,效率低。链表的优点是可以快速插入和删除节点,大小动态分配长度不需要固定。链表不存在越界问题,数组有越界问题。

(41)传入某个属性的set方法的隐含参数的名称是什么?

value,它的类型和属性所声名的类型相同。

(42)如何在C#中实现继承?

答:在类名后加上一个冒号,再加上基类的名称。

(43)C#支持多重继承么?
不支持。可以用接口来实现。

(44)被protected修饰的属性/方法在何处可以访问?
答:在继承或间接继承与这个类的子类中可以访问。

(45)私有成员会被继承么?

会,但是不能被访问。所以看上去他们似乎是不能被继承的,但实际上确实被继承了。

(46)请描述一下修饰符protected internal。

被protected internal修饰的属性/方法只能在它的在同一个程序集(Assembly)中的子类被访问。

(47)C#提供一个默认的无参数构造函数,当我实现了另外一个有一个参数的构造函数时候,还想保留这个无参数的构造函数。这样我应该写几个构造函数?

两个,一旦你实现了一个构造函数,C#就不会再提供默认的构造函数了,所以需要手动实现那个无参数构造函数。

(47)C#中所有对象共同的基类是什么? System.Object.

(48)重载和覆写有什么区别?

重载提供了对一个方法签名的不同参数调用的实现。覆写提供了子类中改变父类方法行为的实现。

(49)在方法定义中,virtual有什么含意?

被virtual修饰的方法可以被子类覆写。

(50)能够将非静态的方法覆写成静态方法么?

不能,覆写方法的签名必须与被覆写方法的签名保持一致,除了将virtual改为override。

(51)可以覆写私有的虚方法么?

不可以,如果一个方法是虚方法,就不应该定义成私有的!

(52)能够阻止某一个类被其他类继承么?

可以,使用关键字sealed。

(53)能够实现允许某个类被继承,但不允许其中的某个方法被覆写么?

可以,标记这个类为public,并标记这个方法为sealed。(注意:这个方法必须是覆盖了父类中的一个虚方法,否则,无法使用sealed)(54)什么是抽象类(abstract class)?

一种不可以被实例化的类。抽象类中一般含有抽象方法,当然也可有具体实现。继承类只有实现过所有抽象类的抽象方法后才能被实例化。

(55)何时必须声明一个类为抽象类?

当这个类中包含抽象方法时,或是该类并没有完全实现父类的抽象方法时。

(56)接口(interface)是什么?

只含有共有抽象方法(public abstract method)的类。这些方法必须在子类中被实现。

(57)为什么不能指定接口中方法的修饰符?
接口中的方法用来定义对象之间通信的契约,指定接口中的方法为私有或保护没有意义。他们默认为公有方法。

(58)可以继承多个接口么? 当然。

(59)那么如果这些接口中有重复的方法名称呢?

这种情况中你可以决定如何实现。当然需要特别得小心。但是在编译环节是没有问题的。

(60) 接口和抽象类的区别是什么?

接口中所有方法必须是抽象的,并且不能指定方法的访问修饰符。抽象类中可以有方法的实现,也可以指定方法的访问修饰符。

(61)如何区别重载方法?

不同的参数类型,不同的参数个数,不同的参数顺序。

(62)const和readonly有什么区别?

const关键字用来声明编译时常量,readonly用来声明运行时常量。

(63)System.String 和System.StringBuilder有什么区别?

System.String是不可变的字符串。System.StringBuilder存放了一个可变的字符串,并提供一些对这个字符串修改的方法。

 (66) 简要说一下.Net的编译过程.

先编译成IL代码,然后在执行中,由JIT再编译成机器码,再执行.

(66)ASP.NET与ASP的区别

区别太多了,最原始的应该是一个是解释性,一个是编译型.一个使用VBS脚本,一个是依靠.Net的框架.

(67).谈一下ASP.NET页面生命周期

 (69)javascript中类库的制作和调用方法

库?编写外部的JS,然后将功能封装到对象中.调用方法?引进来,然后创建对象就用了吧?

(70) AJAX原理及你所知道和使用过的版本

Http的异步请求,然后通过DOM动态修改当前页的Html代码. 没用过什么版本,就是自己调用,还有页面支持的那个异步回调.不过我将代码提了出来,做成了自己需要的. 

(71) WebService使用的协议及简述使用流程

Http的异步请求,然后通过DOM动态修改当前页的Html代码.
没用过什么版本,就是自己调用,还有页面支持的那个异步回调.不过我将代码提了出来,做成了自己需要的.

(72) 谈一下WebService的安全性及相关技术

(73) 事务操作的原理及同库事务及跨库事务的思路

事务原理?同库事务可以由数据库本身来支持,跨库的Windows平台应该在根本上是使用Com+.

(74) 简述你的一个项目,主要的流程及部署

(75) 谈一下你对SOA的理解及熟习的SOA架构

(76)谈一下你对SaaS的理解

SaaS是Software-as-a-service(软件即服务)的简称,是随着互联网技术的发展和应用软件的成熟,而在21世纪开始兴起的一种完全创新的软件应用模式。它与“on-demand software”(按需软件),the application service provider(ASP,应用服务提供商),hosted software(托管软件)所具有相似的含义。它是一种通过Internet提供软件的模式,厂商将应用软件统一部署在自己的服务器上,客户可以根据自己实际需求,通过互联网向厂商定购所需的应用软件服务,按定购的服务多少和时间长短向厂商支付费用,并通过互联网获得厂商提供的服务。用户不用再购买软件,而改用向提供商租用基于Web的软件,来管理企业经营活动,且无需对软件进行维护,服务提供商会全权管理和维护软件,软件厂商在向客户提供互联网应用的同时,也提供软件的离线操作和本地数据存储,让用户随时随地都可以使用其定购的软件和服务。对于许多小型企业来说,SaaS是采用先进技术的最好途径,它消除了企业购买、构建和维护基础设施和应用程序的需要。 在这种模式下,客户不再象传统模式那样花费大量投资用于硬件、软件、人员,而只需要支出一定的租赁服务费用,通过互联网便可以享受到相应的硬件、软件和维护服务,享有软件使用权和不断升级,这是网络应用最具效益的营运模式。

(77)你是否在ASP.NET之外还会JAVA、PHP?

(78)如果让你设计一个登录模块,你会怎么考虑和制作?

(79)如果让你制作日志模块,你会怎么考虑和制作?

(80)如果让你制作用户权限模块,你会怎么考虑和制作?

(81)如果让你做文件上传模块,你会怎么考虑和制作?如果文件大于1G你会怎么考虑设计?

(82)是否了解及使用过WCF、WF、WPF?

(83)Web页面的打印及报表的输出思路?

 

 

(84)报表的制作思路?

 

 

(85)ADO和ADO.NET的区别?

 

第三部分:专有技术的问题:

(86)是否做过GIS方面的项目?用过哪些二次开发包?

 

 

第四部分:项目管理和团队合作方面的问题:

(87)如果给你二个初级程序员帮助你工作,你会怎么安排任务?及怎么控制项目进度?

 

 

第五部分:职业规划方面的问题:

(88)是否了解我公司情况?如果对方不了解,进行相应的介绍。

 

 

(89)是否对这个岗位有兴趣?介绍岗位相应的情况。

 

(90)是否愿意学习岗位相关的行业及技术?简绍相应的背景和技术。

 

第六部分: 询问一下对方期望的薪资和福利。

 

 

 

 

第七部分:有没有什么问题和想法想要询问的

 

 

 

以下收集了关于.NET几大热点问题及简要答案,防止我们回答问题不专业的尴尬。

91).什么是.Net?它主要包括什么?

答:Net是为简化在第三代因特网的高分布式环境下的应用程序开发,基于开放互联网标准和协议之上,实现异质语言和平台高度交互性,而构建的新一代计算和通信平台。 .Net主要包括普通语言运行时(Common Language Runtime)和.Net构架类库92.Net主要的优点有哪些?

答: .Net的主要优点有跨语言,跨平台,安全,以及对开放互联网标准和协议的支持。
.Net支持多种语言的互操作,即在一种语言下开发的组件,可在另一组件下通过面向对象的继承而得以重用,目前.Net支持的语言达二十多种。 .Net通过将各语言先编译成中间语言(IL),然后再执行时用即时(Just In Time)编译器将之编译成本地平台代码来实现异构平台下对象的互操作,目前.Net支持的平台有Windows,Linux和Unix的支持正在开发中。  .Net通过普通语言运行时(Common Language Runtime)来实现资源对象,类型的安全。 .Net通过对HTTP,XML,SOAP,WSDL等Internet标准的强劲支持提供在异构网络环境下获取远程服务,连接远程设备,交互远程应用的编程界面.

93.Net中的普通语言运行时(Common Language Runtime)指什么?它在.Net中处什么位置?
  CLR(Common Language Runtime)普通语言运行时是整个.net framework构建的基础,是实现.Net跨平台,跨语言,代码安全等核心特性的关键。它实际上是驻留在内存里的一段代理代码,负责在整个.net整个执行期间的代码管理工作,比较典型的有:内存管理,线程管理,远程管理,代码强制安全类型等。这些都可称得上.net framework的生命线。实际上,普通语言运行时代理了一部分操作系统的管理功能。
94)..Net构架类库是什么?包括哪些内容?
.Netl构架类库是基于运行时面向对象的特性而建造的,和普通语言运行时紧密集成的一族可重用类(Class)的集合。它大大简化了软件开发的难度,而且很容易与第三方组件无缝集成。
.Net架构类库主要包括对一下编程模型的支持:
1. 控制台应用程序。
2. 脚本和宿主应用程序。
3. Windows Forms应用程序(Windows 桌面GUI应用程序)。
4. ASP.Net应用程序。
5. Web Services应用程序。
6. Windows 服务程序
95.Net支持的开发语言有哪些?.Net语言的互操作性是指什么?  
  .Net声称支持市面上20多种语言,但目前只有微软官方发布的C#,Visual Basic.Net,Managed C++,和Jsript,其他厂商声称正在开发中的支持工具有COBOL,Eiffel,Perl,Smalltalk,Python。
  .Net语言的互操作性是指遵循普通语言运行时(Common Language Runtime)规范的语言在对象继承方面的支持,即用一种语言在.Net平台下开发的类可在另一语言中重用,这通过一种称作微软中间语言MIL来实现,即语言编译器首先将该语言编译成微软中间语言,再在相应平台下编译出本地代码。这一切都是在普通语言运行时的规范下进行。

96.Net支持的平台有哪些?它的跨平台实现得如何?
  目前支持.Net的平台有Windows 2000, NT4 SP6a, Windows Me和Windows 98。其声称支持的平台有Unix,Linux等,目前有三个项目正在开发Linux下的.Net平台:Ximian公司的Mono项目,DotGNU以及 Potable .NET.

97.NetCOM的关系是什么?.Net是否意味着COM的终结?
  COM定义了组件对象间通信的二进制标准,.Net通过组件内置的类型系统提供了类似的机制,它为此提供了另一个途经。.Net并不意味着COM的终结,但必将大大减少开发人员对COM的依赖。.Net 支持COM和.Net组件之间的互操作性,实际上可通过Runtime Callable Wrapper(RCW)来实现在.Net中获取COM组件,通过COM Callable Wrapper(CCW)来实现在COM中获取.Net组件。

98.Net中的中间语言(IL)是什么?它在.Net平台中起什么作用?开发人员可以用中间语言(IL)编程吗?
  .Net中的中间语言是指可以在普通语言运行时规范下,.执行时通过即时(Just In Time)编译器转化为本地代码的,与CPU独立的一族指令集合。它在.Net平台中是实现语言互操作的一个核心环节,所有.Net平台的语言都要先被编译成中间语言(IL)。程序员也可以直接利用中间语言(IL)来编程,但不推荐那样做,中间语言对理解.Net对象某些行为和程序的调试很有帮助

99.Net中的自动垃圾收集是什么?它给.Net平台下的编程带来什么变化?
  .Net垃圾收集器负责整个.Net运行时受管代码的内存分配与释放任务。它通过一定的优化算法来选择收集的对象和时间。程序员只有在释放大量受管资源时可以进行立即强制垃圾收集,在释放非受管资源时采用终止化(Finalize)操作来处理,需要在程序运行中释放的应该实现Dispose()方法,并明确调用。其它时间将资源的回收交由.Net垃圾收集起来做。
100.Net的受管(Managed)代码与非受管(Unmanaged)代码指什么?他们的编码有什么区别?
  .Net的受管代码(Managed Code)是指符合普通语言运行时(Common Language Runtime)规范,在内存中受运行时代码代理进行内存管理,线程管理,远程管理,代码强制安全类型的代码。非受管代码指对内存,文件,数据库等非受管资源进行操作的代码,他们通常不受运行时代码代理管理,是不安全的。对受管代码的编程只需专注于编程的逻辑,对于内存等资源的管理交由普通语言运行时(Common Language Runtime)来负责,而对非受管代码的编程,则要开发人员精心负责各种非受管资源的分配和回收工作。

 

 

.NET 高级部分面试题

(1)   NET新引入了Application Domain的概念,这样他们三个之间有什么区别?引入了Application Domain会带来一些潜在的问题么?

答:AppDomain表示应用程序域,它是一个应用程序在其中执行的独立环境。无法继承此类。多个应用程序域可以在一个进程中运行;但是,在应用程序域和线程之间没有一对一的关联。多个线程可以属于一个应用程序域,尽管给定的线程并不局限于一个应用程序域,但在任何给定时间,线程都在一个应用程序域中执行。

进程可以理解为一个容器,提供进程空间,线程所使用的内存都在进程空间中分配。每个线程有自己的堆栈。APPDomain相当于一个逻辑概念,相当于在进程中逻辑的划分了一些区域,所以线程是可以跨域访问另外的线程。

(2)   Windows Service与普通的EXE在执行过程中有什么区别?

一般前者无界面,有windows的Service服务器负责维护启动和关闭。Exe由用户维护且一般有界面。

没有区别。都是执行文件,不过一个是系统服务,一个是普通软件。有些系统服务是系统的基本服务,随计算机启动而启动。 有些系统服务是另外程序的前提,比如,打印服务,如果没有启动打印服务,打印程序就不能运行。需要向操作系统注册, EXE

直接运行。

(3)   一个进程可以访问的Windows地址空间有多大?等于系统的虚拟内存大小么?这两方面将对系统的设计产生什么样的影响?答: 跟数据总线有关系。一般32位操作系统,寻址空间可以达到4GB,所以一个进程可以访问的地址也为4GB(不过实际上,有2GB是留给操作系统使用的,4M是不可访问的,剩下的空间才供进程使用)。b.不等于虚拟内存。c.寻址空间和数据总线的宽度有关系。虚拟内存会消耗CPU处理时间。因为需要做内外存的转换工作。

(4)  EXE和DLL之间的区别是什么?在系统设计中应该如何选择使用它们?

答: a.Exe有自己的进程空间,dll没有,dll只能被引用后,和exe共享进程空间才能被调用和运行(其实还有rundll32命令可以启动dll,该系统命令本质上就是为其提供进程空间)。b.dll也叫动态链接库,可以将反复使用的共有代码和资源放在动态链接库中,这样在内存中只会有一个副本,节约内存空间(不同的进程根据不同的重定位信息可以定位到制定的dll中)。

(5)   普通的EXE与.NET EXE的执行过程有什么不同?

答: 普通exe可以直接在操作系统上执行,但是.net exe需要jit的及时编译,并在托管环境下(即CLR的控制下)运行

(6)什么是弱类型,什么是强类型?在系统设计中应该首先考虑使用哪种类型?

答:弱类型在一定程度上允许不同类型的数据进行相互操作和运算,但是强类型不允许,因为强类型会做类型检查工作。

(7)PDB文件是作什么用的?里面包含了什么信息?

答: 程序数据库 (PDB) 文件保存着调试和项目状态信息,使用这些信息可以对程序的调试配置进行增量链接。

(8)Cyclomatic Complexity是什么?为什么它很重要?

答: 圈复杂度,用于衡量程序的分支数量。一个正常的方法,分值应该控制在5,6个,如果分支数太大,则最好进行方法的分解,避免badsmell.

(9) 为创建一个critical section以访问某个变量书写一个标准的lock() 并加上double check。

If(m_Instance!=null)

{

        lock(this)

       { 

if(m_Instance!=null))

   {

                  //do something

}

    }

}

(10)为某个对象实现标准的Dispose模式。

Class MyObject:Idisposable

{

       public void Dispose()

       {

              //do something

       }

}   就是实现Idisposable接口,进而实现自定的析构

(11) 什么是FullTrust? 存在于GAC中的 assembly 拥有FullTrust么?

 

(12)下面这个命令是做什么的?gacutil /l | find /i “system”

答: 全局程序集缓存工具使您可以查看和操作全局程序集缓存和下载缓存的内容。

(13)下面这个命令是作什么的? sn -t something.dll

Sn.exe 提供用于密钥管理、签名生成和签名验证的选项。

(14)跨防火墙的 DCOM必须打开哪个端口?端口135是用来做什么的?

(15)有什么办法可以与现有unmanaged code集成?在集成的时候应该考虑什么问题?

(16)简要解释一下OOP与SOA都是用来作什么的?

OOP是一种程序编程架构,包含几个特征:组件,封装,继承,抽象,多态。SOA叫面向服务架构。

(17)XmlSerializer是如何工作的?进程运行XmlSerializer时候需要什么样的ACL权限?

ACL访问控制列表。

(18)在系统设计时,何时应该使用try catch?何时需要避免使用?

(19)Debug.Write()和Trace.Write()之间有什么区别?二者分别应该用于何处?

都是断言。Debug.Write()为调试版本,在发行版本里面不会被执行,而Trace.Write在发行版本中会被执行。

(20)Debug Build和Release Build有什么区别?在执行效率上有什么明显的区别么?

Debug build的版本包含了一些调试信息,执行效率会低一些。

(21) JIT是针对Assembly还是Method发生的?解释一下为什么.NET的设计者要这样做?

简要描述一下GC的执行过程。当内存减少到某个程度之后,CLR启动垃圾回收,将那些不被引用的对象回收并释放所占用的内存。

(21)应该如何选择使用abstract class还是interface?抽象类可以有实现,接口无实现。接口可以多继承,抽象类不行。

(22)在设计一个自定义类型时应如何选择使用Value Type还是Reference Type? 其实要描述的就是引用类型和值类型的区别。可以从内存分布和访问效率两方面谈。

(23)     对于Value Type和Reference Type,a.Equals(b)的默认实现方式有什么不同?答 值类型默认就是指是否相等。引用类型就是比较两个引用是否指向同一个对象。

(24)     .NET中为什么不提供默认的deep copy?如果需要,要如何实现deep copy? 因为深度拷贝涉及到拷贝的级数问题,就是需要深度拷贝到什么层次。在C#中,不可以直接覆写MemberwiseClone方法,可以实现Iclone接口来实现自定义的深度拷贝。

(25)     相对于.NET 1.1,.NET2.0为了避免过度的boxing/unboxing造成的系统开销提供了哪些支持?答:范

(26)     String是Value Type还是Reference Type?为什么.NET中的String对象被设置成immutable(不可变的)?答: 是引用类型。因为字符串对象在操作系统中出现的频率很高,如果为每一个string都分配一个独立的内存,将会是很大的系统开销。所以string 设置为不可变的,就是一种内存驻留技术,本质上就是让同样的字符串都访问同一块内存。比如:s1=”a”,s2=”b”,则s1和s2其实都是指向同一块为”a”的内存;如果现在修改s1=”b”,则s1将不再指向”a”,而是开辟另一块为”b”的内存空间,使s1指向b(其实如果有另一个s3=”b”,则s1就会和s3指向同一个”b”,此时s1不再重新开辟空间)。 

(澄清一下,我发帖的目的不是用来专门给人评价这些问题的好坏的,实际上我所在的公司就考察这些问题。而能够基本上答出来的可以说百里挑一。如果各位觉得这些问题很简单,那么基本上在.NET面试环节就没有什么问题了,同时欢迎提供一些更多的问题。如果还有些不知道,那么不妨静下心来思考一下(或者用15秒搜索一下),没有必要花太多时间来攻击题目的合理性。毕竟,几乎所有的面试都是这样。如果没法改变,我们还是学着适应吧。)

如果你的简历上面说“精通
.NET”,那么下面的问题应该大都可以给出较完美的答案。我会稍后给出一些我的想法,还请各位不吝指正并参与讨论。也欢迎提供给我更多的问题。
这里还有一些基础问题:http://www.cnblogs.com/dflying/archive/2006/04/01/364458.html 

注:对于每个判断是非问题,都要考虑“为什么”与“为什么不”。

  1. ThreadProcess之间有什么区别?.NET新引入了Application Domain的概念,这样他们三个之间有什么区别?引入了Application Domain会带来一些潜在的问题么?
  2. Windows Service与普通的EXE在执行过程中有什么区别?
  3. 一个进程可以访问的Windows地址空间有多大?等于系统的虚拟内存大小么?这两方面将对系统的设计产生什么样的影响?
  4. EXEDLL之间的区别是什么?在系统设计中应该如何选择使用它们?
  5. 普通的EXE.NET EXE的执行过程有什么不同?
  6. 什么是弱类型,什么是强类型?在系统设计中应该首先考虑使用哪种类型?
  7. PDB文件是作什么用的?里面包含了什么信息?
  8. Cyclomatic Complexity是什么?为什么它很重要?
  9. 为创建一个critical section以访问某个变量书写一个标准的lock() 并加上double check
  10. 为某个对象实现标准的Dispose模式。
  11. 什么是FullTrust? 存在于GAC中的 assembly 拥有FullTrust么?
  12. 下面这个命令是做什么的?gacutil /l | find /i “system”
  13. 下面这个命令是作什么的? sn -t something.dll
  14. 跨防火墙的 DCOM必须打开哪个端口?端口135是用来做什么的?
  15. 有什么办法可以与现有unmanaged code集成?在集成的时候应该考虑什么问题?
  16. 简要解释一下OOPSOA都是用来作什么的?
  17. XmlSerializer是如何工作的?进程运行XmlSerializer时候需要什么样的ACL权限?
  18. 在系统设计时,何时应该使用try catch?何时需要避免使用?
  19. Debug.Write()Trace.Write()之间有什么区别?二者分别应该用于何处?
  20. Debug BuildRelease Build有什么区别?在执行效率上有什么明显的区别么?
  21. JIT是针对Assembly还是Method发生的?解释一下为什么.NET的设计者要这样做?
  22. 简要描述一下GC的执行过程。
  23. 应该如何选择使用abstract class还是interface
  24. 在设计一个自定义类型时应如何选择使用Value Type还是Reference Type
  25. 对于Value TypeReference Typea.Equals(b)的默认实现方式有什么不同?
  26. .NET中为什么不提供默认的deep copy?如果需要,要如何实现deep copy
  27. 相对于.NET 1.1.NET2.0为了避免过度的boxing/unboxing造成的系统开销提供了哪些支持?
  28. StringValue Type还是Reference Type?为什么.NET中的String对象被设置成immutable

如果您能较完美的回答其中大多数问题,你已经可以毫无疑问的宣称自己“精通.NET”了。祝各位好运!

 

面向对象的思想主要包括什么?面向对象技术有什么好处?

2008-03-19 12:57

继承 多态 封装
● 封装:用抽象的数据类型将数据和基于数据的操作封装在一起,数据被保护在抽象数据类型内部。
● 继承:子类拥有父类的所有数据和操作。
● 多态:一个程序中同名的不同方法共存的情况。
有两种形式的多态– 重载与重写。

面向对象的好处及其代价
面向对象所以要采用它们,是因为它们有其好处;所以有人不喜欢他们,是因为他们也有其不好的地方.
下面是我由面向对象的特征延伸出来的几点看法:
第一,类具有"独立性".
由于这种独立的存在,使得和其他的"过程也好,对象也罢"能够不彼此牵引.避免"牵一发而动全身"的局面.这有利于维护和调试.
第二,类具有"通用性".
这种通用性,是通过抽象得来的.所谓抽象,就是抽取出事物的共同特征并且加以概括.正是因为这种"通用性"的实现,才造就了"re-use"的可能.
第三,类具有"灵活性".
由于第二个特征的存在,加上客观事物的特殊性,有可能通用的类中一部分成员方法变得"不通用",这个时候通过继承和Overload的机制,使得它能够应付某些特殊情况,从而实现了"灵活性".

在上述前提下,要得这些好处,必须通过系统的思考.而思考也许并不总是愉快的.所以就得为得到这些好处而付出"额外"思考的代价(还包括代码的数量.呵呵有意思...)
面向对象技术的好处

就分析设计层面来说,面向对象技术提供了更高级的抽象能力以及更多的方法和工具,如设计模式;

就实现维护层面来说,面向对象技术使代码重用更容易,且使代码具有可扩展性,便于软件的维护和升级更新。
面向对象是最近非常流行的名词,但是究竟什么是面向对象技术呢?采用面向对象技术的好处是什么?是不是我们用到了面向对象语言,会设计类这种好处就一定会出现呢?下面谈谈我自己的理解。

   1)近代的软件产业发展非常的迅速,但是却出现了让软件开发人员越来越不能忽视的危机,比如,软件的开发成本,尤其是大型软件开发成本、软件维护升级等费用非常的昂贵,针对出现的危机,人们提出了能够提高代码复用等的面向对象技术,面向对象技术的提出可以使客户于软件开发人员、软件开发人员之间的交流更加的顺畅,原因在于:首先,面向对象技术通常对现实世界的对象进行抽象,这种抽象使得即是非专业人员也能明软件要做什么,使得客户于专业的软件开发人员交流起来更加顺畅,节约开发成本;其次,面向对象技术通常会采用封装,继承等技术,这些技术会使得不同的程序模块之间的关联度减小,可以使得开发人员专注于程序的研发,而不是把大量的精力都放到各个模块的协调上。

2)并不是说我们利用了面向对象的语言,比如C++、JAVA,面向对象技术的好处就会出现,实际上在小的程序设计上,可能根本不需要这么复杂。真正的大型软件开发用到时需要采用相应的技术方法,不断的优化,比如瀑布模型法,快速原型法。瀑布模型法主要是把软件分为若干阶段,在每一个阶段,都充分的和客户交流;快速模型法主要是首先提出一个总的模型提交给客户,然后在不断的修改,通常这种方法只适用于较小的工程。无论采用那种方法我们可以遵从一个原则:就是把大的软件项目不断的细化,最后细化到一个个小函数,然后在根据之间的关系封装等。
面向对象技术(OOT)是一种软件开发和程序设计技术。所开发的程序是面向对象程序,直接描述客观世界的对象及其相互关系。例如,银行经理、秘书、职员、顾客、帐本、打印机,直接作为对象出现的程序中。他们相互通信,完成诸如存取款、会计结算、打印报表等业务。以往的编程技术只用数据结构和算法来模拟要完成的业务,虽然可以得到所需计算,但经不起修改。如果增加某项业务,如代营股票,则程序几乎要重编。而现在只要把增加的业务加到顾客、帐本、职员、打印机这些对象上就可以了。
对象是封装了数据和操作的程序块。所谓封装是为这个程序块建立显示的界面。其它对象只能向这个界面发消息,不能访问内部的私有数据和操作。比如我们要求某人“坐下”(发消息),某人接受消息后调整自己的肌肉、神经使自己坐下(操作),从而改变了他的状态(描述姿态的数据变了)。外界不必过问惊动了几条神经,收缩了哪几块肌肉。因此,内部的数据和实现操作的算法若有改动,对其它程序对象没有任何影响。
封装使程序局部化,易修改、好维护,但许多对象有相同的功能时免不了重复,所以面向对象技术有继承的机制。例如,我们描述了“人”这一对象。人有姓名、年龄、职业、住址等数据和吃饭、乘车、上班等操作。我们再设计一个新对象“中国人”时,它将继承“人”的所有数据和操作,再加上“说汉话”、“写汉字”、“身份证号”等“中国人”特有的数据和操作。这样,设计新对象时只要在原有对象基础上作较少的派生,如果运行无误,便将新对象入库,下次又可继续派生。如从中国人派生出“中国男人”、“中国女人”等。于是,库中各类对象按继承关系可形成一棵倒置的树,分枝不断增加,到一定时候一个新程序要用到的对象类库中全有,只要“摘取”出来就可以直接使用,几乎不用编程。所以说,继承支持高度的软件重用。
此外,由于对象自己操作自己的数据。同一消息不同的对象均以自己的方式响应,使得一种消息可有多种响应方式。这叫多态性。例如,“吃饭”这个消息,“中国人”和“俄国人”响应不同(一用筷子,一用刀叉),按过去的编程方法,要分别编出各自的程序,多态性则使程序增删简化。
封装、继承、多态是面向对象程序的主要特征。正是这些特征使程序安全、可靠、可重用、易维护。把这些思想用于硬件、数据库、人工智能技术、分布式计算、网络、操作系统都显示出其优越性。因而,成为当今新兴的计算机技术。特别是多媒体数据只有与相应的操作相联系才能显现出图、声、像,采用封装数据和操作的办法,有力地促进了多媒体应用技术的发展。

前面已说明设计程序就是编写程序欲解决的问题的描述,也就是编写论调。而论调可以只用“名词性概念”和“动词性概念”表现出来,对象又正好是“名词性概念”的实现,而利用前面说的没有成员变量的类来映射“动词性概念”就可以将其转换为对象。因此,一个世界,可以完全由对象组成,而将算法所基于的世界只用对象表现出来,再进行后续代码的编写,这种编程方法就被称作面向对象的编程思想。
注意,先设计算法应基于的世界,再全部用对象将其表述出来,然后再设计算法,最后映射为代码。但前面在编写商人过河问题时是直接给出算法的,并没有设计世界啊?其实由于那个问题的过于简单,我直接下意识地设计了世界,并且用前面所说的河岸论来描述它。应注意世界的设计完全依赖于问题,而准确地说,前面我并没有设计世界,而是设计了河岸论来描述问题。
接着,由于对象就是实例,因此以对象来描述世界在C++中就是设计类,通过类的实例来组合表现世界。但应注意,面向对象是以对象来描述世界,但也描述算法,因为算法也会提出一些需要被映射的概念,如前面商人过河问题的算法中的过河方案。但切记,当描述算法时操作了描述世界时定义的类,则一定要保持那个类的设计,不要因为算法中对那个类的实例的操作过于复杂而将那部分算法映射为这个类的一个成员函数,因为这严重遮蔽了算法的实现,破坏了程序的架构。如一个算法是让汽车原地不停打转,需要复杂的操作,那么难道给汽车加一个功能,让它能原地不停地打转?!这是在设计类的时候经常犯的错误,也由于这个原因,一个面向对象编写的代码并不是想象的只由类组成,其也可能由于将算法中的某些操作映射成函数而有大量的全局函数。请记住:设计类时,如果是映射世界里的概念,不要考虑算法,只以这个世界为边界来设计它,不要因为算法里的某个需要而给它加上错误的成员。
因此,将“名词性概念”映射成类,“名词性概念”的属性和状态映射为成员变量,“名词性概念”的功能映射为成员函数。那么“动词性概念”怎么办?映射成没有成员变量的类?前面也看见,由于过于别扭,实际中这种做法并不常见(STL中也只是将其作为一种技巧),故经常是将它映射为函数,虽然这有背于面向对象的思想,但要易于理解得多,进而程序的架构要简明得多。
随着面向对象编程思想的问世,一种全新的设计方式诞生了。由于它是如此的好以至于广为流传,但理解的错误导致错误的思想遍地而生,更糟糕的就是本末倒置,将这个设计方式称作面向对象的编程思想,它的名字就是封装。


封装

先来看现在在各类VC教程中关于对象的讲解中经常能看见的如下的一个类的设计。
class Person
{ private: char m_Name[20]; unsigned long m_Age; bool m_Sex;
public: const char* GetName() const; void SetName( const char* );
unsigned long GetAge() const; void SetAge( unsigned long );
bool GetSex() const; void SetSex( bool );
};
上面将成员变量全部定义为private,然后又提供三对Get/Set函数来存取上面的三个成员变量(因为它们是private,外界不能直接存取),这三对函数都是public的,为什么要这样?那些教材将此称作封装,是对类Person的内部内存布局的封装,这样外界就不知道其在内存上是如何布局的并进而可以保证内存的有效性(只由类自身操作其实例)。
首先要确认上面设计的荒谬性,它是正宗的“有门没锁”毫无意义。接着再看所谓的对内存布局的封装。回想在《C++从零开始(十)》中说的为什么每个要使用类的源文件的开头要包含相应的头文件。假设上面是在Person.h中的声明,然后在b.cpp中要使用类Person,本来要#include "Person.h",现在替换成下面:
class Person
{ public: char m_Name[20]; unsigned long m_Age; bool m_Sex;
public: const char* GetName() const; void SetName( const char* );
unsigned long GetAge() const; void SetAge( unsigned long );
bool GetSex() const; void SetSex( bool );
};
然后在b.cpp中照常使用类Person,如下:
Person a, b; a.m_Age = 20; b.GetSex();
这里就直接使用了Person::m_Age了,就算不做这样蹩脚的动作,依旧#include "Person.h",如下:
struct PERSON { char m_Name[20]; unsigned long m_Age; bool m_Sex; };
Person a, b; PERSON *pP = ( PERSON* )&a; pP->m_Age = 40;
上面依旧直接修改了Person的实例a的成员Person::m_Age,如何能隐藏内存布局?!请回想声明的作用,类的内存布局是编译器生成对象时必须的,根本不能对任何使用对象的代码隐藏有关对象实现的任何东西,否则编译器无法编译相应的代码。
那么从语义上来看。Person映射的不是真实世界中的人的概念,应该是存放某个数据库中的某个记录人员信息的表中的记录的缓冲区,那么缓冲区应该具备那三对Get/Set所代表的功能吗?缓冲区是缓冲数据用的,缓冲后被其它操作使用,就好像箱子,只是放东西用。故上面的三对Get/Set没有存在的必要,而三个成员变量则不能是private。当然,如果Person映射的并不是缓冲区,而在其它的世界中具备像上面那样表现的语义,则像上面那样定义就没有问题,但如果是因为对内存布局的封装而那样定义类则是大错特错的。
上面错误的根本在于没有理解何谓封装。为了说明封装,先看下MFC(Microsoft Foundation Class Library——微软功能类库,一个定义了许多类的库文件,其中的绝大部分类是封装设计。关于库文件在说明SDK时阐述)中的类CFile的定义。从名字就可看出它映射的是操作系统中文件的概念,但它却有这样的成员函数——CFile::Open、CFile::Close、CFile::Read、CFile::Write,有什么问题?这四个成员函数映射的都是对文件的操作而不是文件所具备的功能,分别为打开文件、关闭文件、从文件读数据、向文件写数据。这不是和前面说的成员函数的语义相背吗?上面四个操作有个共性,都是施加于文件这个资源上的操作,可以将它们叫做“被功能”,如文件具有“被打开”的功能,具有“被读取”的功能,但应注意它们实际并不是文件的功能。
按照原来的说法,应该将文件映射为一个结构,如FILE,然后上面的四个操作应映射成四个函数,再利用名字空间的功能,如下:
namespace OFILE
{
bool Open( FILE&, … ); bool Close( FILE&, … );
bool Read( FILE&, … ); bool Write( FILE&, … );
}
上面的名字空间OFILE表示里面的四个函数都是对文件的操作,但四个函数都带有一个FILE&的参数。回想非静态成员函数都有个隐藏的参数this,因此,一个了不起的想法诞生了。
将所有对某种资源的操作的集合看成是一种资源,把它映射成一个类,则这个类的对象就是对某个对象的操作,此法被称作封装,而那个类被称作包装类或封装类。很明显,包装类映射的是“对某种资源的操作”,是一抽象概念,即包装类的对象都是无状态对象(指逻辑上应该是无状态对象,但如果多个操作间有联系,则还是可能有状态的,但此时它的语义也相应地有些变化。如多一个CFile::Flush成员函数,用于刷新缓冲区内容,则此时就至少有一个状态——缓冲区,还可有一个状态记录是否已经调用过CFile::Write,没有则不用刷新)。
现在应能了解封装的含义了。将对某种资源的操作封装成一个类,此包装类映射的不是世界中定义的某一“名词性概念”,而是世界的“动词性概念”或算法中“对某一概念的操作”这个人为定出来的抽象概念。由于包装类是对某种资源的操作的封装,则包装类对象一定有个属性指明被操作的对象,对于MFC中的CFile,就是CFile::m_hFile成员变量(类型为HANDLE),其在包装类对象的主要运作过程(前面的CFile::Read和CFile::Write)中被读。
有什么好处?封装提供了一种手段以将世界中的部分“动词性概念”转换成对象,使得程序的架构更加简单(多条“动词性概念”变成一个“名词性概念”,减少了“动词性概念”的数量),更趋于面向对象的编程思想。
但应区别开包装类对象和被包装的对象。包装类对象只是个外壳,而被包装的对象一定是个具有状态的对象,因为操作就是改变资源的状态。对于CFile,CFile的实例是包装类对象,其保持着一个对被包装对象——文件内核对象(Windows操作系统中定义的一种资源,用HANDLE的实例表征)——的引用,放在CFile::m_hFile中。因此,包装类对象是独立于被包装对象的。即CFile a;,此时a.m_hFile的值为0或-1,表示其引用的对象是无效的,因此如果a.Read( … );将失败,因为操作施加的资源是无效的。对此,就应先调用a.Open( … );以将a和一特定的文件内核对象绑定起来,而调用a.Close( … );将解除绑定。注意CFile::Close调用后只是解除了绑定,并不代表a已经被销毁了,因为a映射的并不是文件内核对象,而是对文件内核对象操作的包装类对象。
如果仔细想想,就会发现,老虎能够吃兔子,兔子能够被吃,那这里应该是老虎有个功能是“吃兔子”还是多个兔子的包装类来封装“吃兔子”的操作?这其实不存在任何问题,“老虎吃兔子”和“兔子被吃”完全是两个不同的操作,前者涉及两种资源,后者只涉及一种资源,因此可以同时实现两者,具体应视各自在相应世界中的语义。如果对于真实世界,则可以简略地说老虎有个“吃”的功能,可以吃“肉”,而动物从“肉”和“自主能动性”多重继承,兔子再从动物继承。这里有个类叫“自主能动性”,指动物具有意识,能够自己动作,这在C++中的表现就是有成员函数的类,表示有功能可以被操作,但收音机也具有调台等功能,难道说收音机也能自己动?!这就是世界的意义——运转。

方法——世界的驱动方式
算法就是方法,前面已说过其由操作和被操作的资源组成,即资源的类型和操作的类型。方法指出如何使用世界中定义出的各种操作,但并不执行。由前面的阐述,世界可以只由对象组成,当对象产生后,世界中所有对象的状态和属性,即成员变量,的一份拷贝,称作世界的状态的一份快照,而世界的状态的变化称作世界的运转。世界的状态就是世界中所有对象的状态和属性,要改变它,就是要执行世界定义的操作,但只能通过方法指出如何执行它以改变世界的状态,进而驱动世界,即使世界定义的操作被执行才能驱动世界。
上面越说越远了,感觉虚得很,有什么意义?考虑为什么要提出世界这个概念。世界是我们欲编程解决的问题所基于的规则集合体,而设计程序就是设计描述世界的论调,然后在这个论调上设计算法,编写出代码,执行代码,得到结果。“得到结果”?!什么是结果?即世界最终状态中的某一部分,如求圆周率的值。这其实是目的,但值得注意的是目的不止这种。代码执行的过程往往是另一种目的,如将数据保存到某个文件中;将文件打开编辑再保存等,这种目的并不关心世界的状态最后如何。而世界的状态的变化过程,也就是世界的运转则是另一种非常流行的目的——电子游戏。
不管什么样的目的,都需要改变世界的状态,即要驱动世界运转,也就必须使世界定义的操作被执行,而这只能通过方法来实现。因此在设计算法时,也就决定了驱动世界的方式。
对于上面的第一种目的,由于是要看世界的最终状态,因此一直连续执行操作到最后。在《C++从零开始(八)》中给出的商人过河的例子就在通过算法得到结果后直接调用printf打印出结果并结束。对于第二种目的,由于要的是执行的过程,因此也可直接连续执行操作到完。但这种目的往往要求由用户决定何时执行且执行不止一段代码,如文件打开后,直到用户给出命令(通过键盘或鼠标或其它输入方式)后才进行编辑操作,且用户可能随机地执行不同的编辑操作,最后也由用户决定是否保存文件。这种世界的运转完全由用户控制的世界驱动方式称为用户驱动方式。这里的算法仅仅是如何打开、保存文件,如何编辑数据,但由于决定是用户驱动方式,则算法就必须修改以实现这种驱动方式。再看第三种目的,要的是世界的状态的变化,则前面两种都可以。但很明显,第一种变化过程不能持续,连续执行完就完;第二种由用户驱动,则太麻烦。因此往往都会有个循环,在游戏编程中一般称其为主循环,每次循环都按照一定的规则改变世界中部分对象的状态,此称作循环驱动方式。每次循环,都会被改变状态的对象就被称作具有自主能动性,如前面提到的动物的实例。除此以外的就不称作具有自主能动性,如前面提到的收音机的实例。同样,游戏中的算法依旧不会涉及到上面提到的循环驱动方式,因此必须修改算法以实现循环驱动方式。
上面将那么多只为了说明一点,已经不能再如《C++从零开始(八)》中说的那几步来编写程序了,下面给出一个方法。
1. 当得到一个问题,应同时得到这个问题的算法(程序员并不是科学家),或由客户给出或由于过于简单而直接得出。
2. 由问题抽象设计出它的描述,即前面说的论调,也就是所谓的程序设计。
3. 将之前给出的算法用刚设计出的论调进行描述,并完善这个论调(因为算法可能带入一些原来世界中并不存在的概念)。
4. 由需要决定使用何种世界驱动方式,并实现以完善算法和论调(世界的驱动方式也可能带入一些原来并不存在的概念)。

 类间关系: 依赖,关联,组合,聚合

http://blog.csdn.net/starryheavens/archive/2009/10/15/4676551.aspx

强命名弱命名及程序集相关

http://www.cnblogs.com/3echo/archive/2006/02/14/330579.aspx

http://www.cnblogs.com/lislok/archive/2008/10/13/1310227.html