我做技术主管时出的一份C#笔试题(附答案)

1、 基础知识

 

1) 值类型与引用类型

下面类型哪些是值类型?哪些是引用类型?

           i.          class enum struct delegate interface

        ii.          object int string float DateTime

 

【答案】

值类型有:enum struct int float DateTime

引用类型有:class delegate interface object string

 

特别要注意的是:string是引用类型

 

值类型与引用类型的区别:

1、内存分配方式不同:

值类型所占的内存区域是连续的,至于是分配在堆上还是栈上,有以下几种情况:

1)     如果值类型Struct1用来定义局部变量,那么它总是分配在栈上;

2)     如果值类型Struct1用来定义引用类型Class1的字段,那么Struct1总是分配在堆上的;

3)     如果值类型Struct1用来定义值类型Struct2的字段,那么Struct1的分配方式取决于Struct2是分配在堆上还是栈上;

4)     如果把值类型Struct1赋予一个引用类型Class1(这种情况通常见于把一个值类型赋予object变量,或赋予一个接口),这时会在堆上建立一个Struct1的拷贝,此过程称之为“装箱”;

 

引用类型的内存区域由两部分组成:一部分为引用(类似于C++中的指针),另一部分为实际的对象,对象本身总是分配在堆上的,而引用分配在堆上还是栈上取决于具体的情况:

1)     如果定义局部变量,那么引用是分配在栈上的;

2)     如果用于定义引用类型的字段,那么引用是分配在堆上的;

3)     如果用于定义值类型的字段,那么引用的分配方式取决于该值类型分配在堆上还是栈上;

 

在堆上和栈上的内存分配有如下的区别:

1)     在栈上定义的对象(或引用),可以在出栈的时候迅速释放,而不必等待无用内存回收器来回收;栈上定义的对象无法持久存储;

2)     栈的空间有限,而堆的空间比较大;

 

2、变量传递方式不同

引用类型在传递的时候,只传递引用本身,而对象只有一个;

值类型在传递的时候会进行对象的拷贝;

 

3、对象释放的方式不同

在对象是否有效的判断上,引用类型是进行引用计数,当引用计数为0时,那么它就会被标为无效,而等待无用内存回收器来收集;

值类型如果分配在堆上,则会分情况而定,如果是作为引用类型的字段而被分配在堆上,则与该对象同存共亡,如果以装箱的方式而分配在堆上,则也与引用类型一样进行引用计数;

如果值类型是分配在栈上,则它的生存期与进栈出栈有关,一对花括号表示一个域,花括号中嵌套的花括号是它的子域,当值类型在进入直接包含它的域的时候被分配,而出域时被释放。

值类型和引用类型都有释构函数,在对象的生存期终止时,值类型会立即执行析构函数,而引用类型是等无用内存收集器运行时执行;无用内存回收器的运行会引起应用程序的暂停,如果析构函数比较耗时,那么将会引起应用程序明显的停顿,这是我们不推荐写析构函数的原因。(但有的情况下析构函数还是比较有价值的)

 

4、对象是否相等的比较方式不同

如果没有重载==运行符,那么引用类型的相等的判断,是两个引用是否引用了同一个对象;值类型如果要进行是否相等的判断,必须重载==运算符;

 

5、默认值及构造方式不同

引用类型可以不引用任何对象,此时它的值为nullnull是引用类型的默认值;值类型的默认值比较复杂,对于基元类型(intlongfloatdouble),默认值为0bool的默认值为false,复合的值类型,是把各个字段都取其默认值;

在对象的构造上,引用类型默认有一个无参构造函数,但如果定义了其它的构造函数,那么该无参构造函数被自动删除;值类型也有一个无参构造函数,但如果定义了其它构造函数,该无参构造函数依然存在,我们也不能明确定义一个无参构造函数,并且在定义的其它构造函数中,必须对所有字段进行赋值,否则会出现编译错误;

 

6、类层次结构不同

引用类型可以自由地派生,但值类型具有固定的类层次结构,其中struct类型是派生于System.ValueTypeenum类型派生于System.Enum,而System.Enum派生于System.ValueType;并且所有的值类型都是密封的,我们不能把值类型用作其它类型的基类;

 

7、如何在值类型与引用类型中选择

如果我们定义一个类型,通常情况下应该定义为引用类型,引用类型在参数传递的效率上具有优势;

值类型由于内存结构比较简单,它在创建和分配的效率上具有优势(不需要引用计数);但由于值类型在传递的时候会引起拷贝,所以值类型的尺寸不适合定义得过大;

定义值类型和引用类型的初衷也是不同的,值类型用于数据的简单存储,例如intlongfloatdouble等,它们不会有多少与架构相关的东西;而引用类型的类层次结构的灵活性,决定了它是定义软件架构的基石;

.NET已经为我们提供了一些值类型,例如intlongfloatdouble等,这些称为基元类型,通常情况下,我们是把这些基元类型进行组合,形成自己的更有意义的值类型,例如定义坐标(x,y),定义一个值类型Point比用两个int来表示更有意义,并且还可以在Point中定义一些有意义的方法,或重载一些运算符等;

 

2) 非静态成员与静态成员

写出下面代码的输出结果:

class MyClass

{

   public MyClass() { v1++; v2++; }

   public static int v1;

   public int v2;

}

 

// 注意:为了书写方便,没有将下面的代码放在函数中,下同

MyClass mc1 = new MyClass(), mc2 = new MyClass();

Console.WriteLine(“{0} {1} {2}”, MyClass.v1, mc1.v2, mc2.v2);

 

【答案】

2 1 1

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值