2011年.NET面试题总结---献给即将找工作的同行们<四>

什么叫应用程序域

一种边界,它由公共语言运行库围绕同一应用程序范围内创建的对象建立(即,从应用程序入口点开始,沿着对象激活的序列的任何位置)。

应用程序域有助于将在一个应用程序中创建的对象与在其他应用程序中创建的对象隔离,以使运行时行为可以预知。隔离正在运行的应用程序。

一个单独的进程中可以存在多个应用程序域。应用程序域可以理解为一种轻量级进程。起到安全的作用。占用资源小。

就是为安全性,可靠性,隔离性,和版本控制,及卸载程序提供的隔离边界。它通常由运行库宿主创建,应用程序域提供了一个更安全,用途更广的处理单元。

什么是强类型,什么是弱类型?哪种更好些?为什么?

    强类型是在编译的时候就确定类型的数据,在执行时类型不能更改,而弱类型在执行的时候才会确定类型。没有好不好,二者各有好处,强类型安全,因为它事先已经确定好了,而且效率高。一般用于编译型编程语言,如c++,java,c#,pascal,弱类型相比而言不安全,在运行的时候容易出现错误,但它灵活,多用于解释型编程语言,如javascript,vb

什么是受管制的代码?什么是强类型和弱类型系统? CTSCLSCLR分别作何解释?

1)受管制的代码:.NET环境中运行的任何代码都称为受管制的代码(unmanaged code).NET外部的其他代码也运行在Windows上,这些代码称为未受管制的代码(unmanaged code)

2)强类型和弱类型的区别在与,在编码过程中是否要指定数据类型,作为强类型必须指定数据类型,编译器为其分配相应的存储空间(如   c   ,pascal   )否则编译出错。而弱类型不一定需要指定数据类型,编译器会用相同的空间去分配各种类型,除非你指定了(如basic)。作为强类型语言,在编译阶段的安全性要高于弱语言型。

强类型系统:RTTI:类型识别系统。  

3CLRCommon Language Runtime)的全称是公共语言运行库,读者可以把CLR理解为一个包含运行.NET程序的引擎和一堆符合公共语言基础结构的类库的集合。CLR是一个规范的实现,我们开发的几乎所有的.NET程序都基于CLR的类库来实现,并且运行在CLR提供的运行引擎之上。所谓.NET框架,指的就是公共语言运行库。

    公共语言基础(CLI)是微软公司向ECMA提交的一份语言和数据格式规范,CLR是目前为止唯一一个公共语言基础的实现版本。

         CTSCommon Type System)的全称是通用类型系统。前文已经介绍了公共语言基础(CLI)的概念,微软公司提交的CLI规范,包括了公共类型系统(CTS)、公共中间语言(CIL)、底部文件格式以及元数据格式等。公共类型系统定义了一个能够在CLR上运行的语言规范。尽管有很多语言本身不符合CTS规范,但是通过加强编译器,改变语言附加规范等手段,使得许多语言能够编写出能在CLR上运行的程序。

    一种语言编写的程序编译能够在CLR上运行,并不代表这种语言本身完全符合CTS的规范。例如C++语言,仍然保持了其不符合CTS规范的部分,并且在编译时把这部分不符合CTS的代码编译成原始代码而非中间代码。  

CLSCommon Language Specification)的全称是通用语言规范,是CTS的一个子集,它定义了希望编写在.NET平台上运行的程序的语言所需符合的最小规范。正因为.NET允许由不同语言编写的程序一起执行,所以才制定出CLS规范,用以避免不同语言特性产生的错误。

.net中哪项技术(CLRCTSCLS)实现跨多语言?

CLR

CLRIL分别是什么含义?

         CLR(公共语言运行库):能管理内存,能够轻松地设计其对象可以跨语言互动的组件和应用程序,编译一次,并可以在任何支持运行库的CPU和操作系统上运行,跨语言集成(特别是跨语言继承)

    公共语言运行时,类似于Java中的JVMJava虚拟机;在.Net环境下,各种编程语言使用一种共同的基础资源环境,这就是CLRCLR将直接与操作系统进行通信,而编程语言如C#.NET将尽量避免直接与操作系统直接通信,加强了程序代码的执行安全性,可以这样看:CLR就是具体的编程语言如:C#.NET与操作系统之间的翻译,同时它为具体的编程语言提供了许多资源。

 

         IL(中间语言):可用于语言互操作性,IL不是字节代码,但很接近字节代码,因此执行应用程序时,IL到机器代码的转换要快很多。独立于CPU的指令集。由CLR转换为特定于CPU的代码。

         IL中间语言,也称MSIL,微软中间语言,或CIL,通用中间语言;所有.NET源代码(不管用哪种语言编写)在进行编译时都被编译成IL。在应用程序运行时被即时(Just-In-TimeJIT)编译器处理成为机器码,被解释及执行。

对象能否调用静态方法

对象能调用静态方法。

PID是什么?在做系统的故障排除时如何使用它?

         PID是进程编号,在系统发现故障的时候,可以根据它寻找故障所发生的具体进程,并且可通过visual studio.netide将故障进程附加到进程中进行调试(debug)

单个TCP/IP端口上能够被多少个进程侦听?

1个

描述一下C#中索引器的实现过程,是否只能根据数字进行索引?

    索引器可以使客户程序很方便地访问类中的集合或数组,类似通过索引访问数组,并且索引器向客户程序隐藏了内部的数据结构。

    类似于属性,访问类或结构的集合或数组时,可以用索引器实现,索引器用this关键字声明,声明方法如下:

数据类型 this[参数列表]

{

         get

{

        以参数为索引返回集合或数组数据

}

set

{

        分配值到参数索引的元素

}

}

例:自己建立一个数组

using System;

class MyArray

{

    private string[] str = new string[5];

    //定义索引器,并有可读可写属性,用this声明属性,接收一个整型类型参数

    public string this[int i]

    {

        get

        {

            return str[i];

        }

        set

        {

            str[i] = value;

        }

    }

    //获得数组长度

    public int Length

    {

        get

        {

            return str.Length;

        }

    }

}

public class LxIndex

{

    static void Main(string[] args)

    {

        MyArray ma = new MyArray();

        //给数组赋值

        Console.WriteLine("给数组赋值,请输入数组元素值:");

        for (int i = 0; i < ma.Length; i++)

        {

            ma[i] = Console.ReadLine();

        }

        //输出数组中的元素

        Console.WriteLine("你输入的内容是:");

        for (int i = 0; i < ma.Length; i++)

        {

            Console.Write(ma[i] + " ");

        }

    }

}

结果:

给数组赋值,请输入数组元素值:

78

tom

**

100

23

你输入的内容是:

78 tom ** 100 23 请按任意键继续. . .

    不是。索引器可以用任意类型进行索引。

MVC模式

MVC(Model View Controller)模型-视图-控制器

模型负责业务领域的事情,视图负责显示的事情,控制器把数据读取出来填充模型后模型交给视图去处理。而各种验证应该是在模型里处理了。它强制性的使应用程序的输入、处理和输出分开。MVC最大的好处是将逻辑和页面分离。

Assembly.Load("foo.dll"); 这句话是否正确?

错误,正确的应该是Assembly.Load("foo"); 或者Assembly.LoadFrom("foo.dll");

DateTime是否可以为null?

不能,因为其为Struct类型,而结构属于值类型,值类型不能为null,只有引用类型才能被赋值null

using() 语法有用吗?什么是IDisposable?它是如何实现确定性终结的

有用,实现了IDisposiable的类在using中创建,using结束后会自定调用该对象的Dispose方法,释放资源。不明白什么是确定性终结

三层架构,用.NetB/S结构的系统,您是用几层结构来开发,每一层之间的关系以及为什么要这样分层?

表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)。目的即为了“高内聚,低耦合”的思想。

表现层(UI):通俗讲就是展现给用户的界面,即用户在使用一个系统的时候的所见所得。

    业务逻辑层(BLL):业务层一般分为二层,业务表观层实现与表示层的沟通,业务规则层实现用户密码的安全等。

表示层:为了与用户交互例如用户添加表单针对具体问题的操作,也可以说是对数据层的操作,对数据业务逻辑处理。

数据访问层(DAL):该层所做事务直接操作数据库,针对数据的增添、删除、修改、更新、查找等每层之间是一种垂直的关系。

三层结构是N层结构的一种,一般来说,层次之间是向下依赖的,下层代码未确定其接口(契约)前,上层代码是无法开发的,下层代码接口(契约)的变化将使上层的代码一起变化。

优点: 分工明确,条理清晰,易于调试,而且具有可扩展性。

缺点: 增加成本。

C#函数中无参数修饰符、out修饰符、params修饰符、ref修饰符的区别

无参数修饰符:表示按值传递

out修饰符:表示按引用传递,传递前不需赋初值,但在传入的方法内赋值,否则报错

ref修饰符:表示按引用传递,传递前必须赋初值,否则报错

params修饰符:可将不确定个数的一组相同类型的数据作为参数传递,函数签名中只能有一个params修饰符,并且应为最后一个参数。

ref out有什么不同?

      方法参数上的 ref 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。若要使用 ref 参数,必须将参数作为 ref 参数显式传递到方法。ref 参数的值被传递到 ref 参数。传递到 ref 参数的参数必须最先初始化。将此方法与 out参数相比,后者的参数在传递到 out 参数之前不必显式初始化。属性不是变量,不能作为 ref 参数传递。如果两种方法的声明仅在它们对 ref 的使用方面不同,则将出现重载。但是,无法定义仅在 ref out 方面不同的重载。

     方法参数上的 out 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。

    当希望方法返回多个值时,声明 out 方法非常有用。使用 out 参数的方法仍然可以返回一个值。一个方法可以有一个以上的 out 参数。若要使用 out 参数,必须将参数作为 out 参数显式传递到方法。out 参数的值不会传递到 out 参数。不必初始化作为 out 参数传递的变量。然而,必须在方法返回之前为 out 参数赋值。属性不是变量,不能作为 out 参数传递。如果两个方法的声明仅在 out 的使用方面不同,则会发生重载。不过,无法定义仅在 ref out 方面不同的重载。

 

extern 是什么意思?

extern 修饰符用于声明由程序集外部实现的成员函数,经常用于系统API函数的调用(通过 DllImport )。注意,和DllImport一起使用时要加上 static 修饰符

也可以用于对于同一程序集不同版本组件的调用(用 extern 声明别名)

不能与 abstract 修饰符同时使用

using System.Runtime.InteropServices;

using System;

namespace TestExtern

{

    class ClassHello

    {

        //externDllImport一起使用时必须再加上一个static修饰符

        [DllImport("User32.dll")]

        public static extern int MessageBox(int Handle, string Message, string Caption, int Type);

        static void Main()

        {

            string myString;

            Console.Write("请输入提示信息: ");

            myString = Console.ReadLine();

            MessageBox(0, myString, "我的测试", 0);

        }

    }

}

结果:

 

2011年.NET面试题总结---献给即将找工作的同行们四 - 醉梦昆仑 - .
 

对象构造器

    使用对象构造器,可以使初始化对象像初始化数组一样简单,即在构造函数后直接添加多个初始化语句代码,并用逗号分隔,整体用{}括起来,定义形式如下:

        类型声明 实例名称 = new 类型名称() {初始化语句1,初始化语句2};

    如果相同成员的不同初始化语句,则以最右面的语句为准。初始化的顺序是先执行构造函数的语句,然后执行对象构造器中的语句。如下例:

Snake s = new Snake () {name="眼镜蛇",length=12,weight=20};

C#匿名类型的的实际应用

通过var和对象构造器,声明一个没有名称(其名称是由编译器分配的)的类,同时创建并初始化成员。如:var pc1 = new {cpu="Intel",memory="AMD"};

如果程序仅仅需要临时一组数据,则用匿名类型比较合适,匿名类型编译后,仍然是一个普通的密封类,不可派生其他类,只是名称是由编译器分配的,利用对象构造器初始化的成员,具有只读属性。匿名内部类同样有构造函数用于初始化成员,只是创建时不需要显式调用。如下列:

constreadonly区别

都可以标识一个常量。主要有以下区别:

1、初始化位置不同。const必须在声明的同时赋值;readonly即可以在声明处赋值,也可以在静态构造方法(必须是静态构造方法,普通构造方法不行里赋值。

2、修饰对象不同。const即可以修饰类的字段,也可以修饰局部变量;readonly只能修饰类的字段

3const是编译时常量,在编译时确定该值;readonly是运行时常量,在运行时确定该值。

4const默认是静态的;而readonly如果设置成静态需要显示声明

5、修饰引用类型时不同,const只能修饰string或值为null的其他引用类型;readonly可以是任何类型。

如果类型限制了不能在编译时确定它的值,可以使用static readonly来代替。

请解释virtual的含义?

     virtual 关键字用于修改方法或属性的声明,在这种情况下,方法或属性被称作虚拟成员。虚拟成员的实现可由派生类中的重写成员更改。

    调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。默认情况下,方法是非虚拟的。不能重写非虚方法。不能将 virtual 修饰符与以下修饰符一起使用:static   abstract   override除了声明和调用语法不同外,虚拟属性的行为与抽象方法一样。

    在静态属性上使用 virtual 修饰符是错误的。

    通过包括使用 override 修饰符的属性声明,可在派生类中重写虚拟继承属性

sealednewvirtualabstractoverride关键字的区别

sealed修饰类代表密封类,不能被继承,修饰方法代表密封方法,不能被重写。通常用于实现第三方类库时不想被客户端继承,或用于没有必要再继承的类以防止滥用继承造成层次结构混乱

new 显式隐藏基类的成员。不用new隐藏基类的成员也可以,但会给出警告。

virtual为了子类来重写的,子类需要override,如果不用会给个警告

abstract可以修饰类,方法,属性,索引器及事件。

override子类重写基类的abstractvirtual成员,。不能重写非虚拟方法或静态方法

newoverride相同点和区别

相同点:都可以对基类成员进行隐藏,都可以用base调用基类的成员

不同点:

1、用override重写基类的方法,要求与基类必须有完全相同的访问修饰符、返回值类型和方法名称名称,参数,异常。new不用

2、用override重写基类的方法,要求基类的方法必须为虚拟的,抽象的或重写的virtualabstract,override),而new不必要

3、继承后,用一个基类的对象调用基类的virtual方法时,override重写的子类方法会被访问,而new重写的子类方法不会被访问(只访问基类的virtual方法)

4new作为运算符时,创建对象,调用构造函数。new 用于约束时 用于在泛型声明中,约束指定泛型类声明中的任何类型参数都必须有公共的无参数构造函数。

using System;

public class BaseClass

{

    public BaseClass()

    {

        Console.WriteLine(" 基类构造");

    }

    //使用virtual才可以在子类中使用override,而new不必要

    public virtual void Method()

    {

        Console.WriteLine(" 基类.Method()");

    }

}

public class ClassA : BaseClass

{

    public ClassA()

    {

        Console.WriteLine(" A.构造");

    }

    public override void Method()

    {

        //base.Method();

        Console.WriteLine(" A.Method() in override");

    }

}

public class ClassB : BaseClass

{

    public ClassB()

    {

        Console.WriteLine(" B.构造");

    }

    public new void Method()

    {

        //base.Method();

        Console.WriteLine(" B.Method() in new");

    }

}

 

 

class Program

{

    static void Main(string[] args)

    {

        BaseClass ba1 = (BaseClass)new ClassA();//类型转换

        //override重写方法,是基类的一个派生,

        //所以这里通过基类的虚函数,会访问到派生类的方法。

        ba1.Method();

        Console.WriteLine(" =================");

 

        BaseClass bb2 = (BaseClass)new ClassB();//类型转换

        //new重写方法,是一个和基类无关的新方法,

        //所以这里基类调用的时候,访问基类的方法。

        bb2.Method();

        Console.WriteLine(" =================");

 

        ClassA a1 = new ClassA();

        a1.Method();

        Console.WriteLine(" =================");

 

        ClassB b2 = new ClassB();

        b2.Method();

        Console.WriteLine(" =================");

        Console.ReadKey();

 

    }

}

 

运行结果:

 基类构造

 A.构造

 A.Method() in override

 =================

 基类构造

 B.构造

 基类.Method()

 =================

 基类构造

 A.构造

 A.Method() in override

 =================

 基类构造

 B.构造

 B.Method() in new

 =================

posted @ 2011-04-04 10:37  peterlee  阅读(216)  评论(0)    收藏  举报