(1)const和staticreadonly的区别是什么?
(2)XmlSerializer如何工作?
(3)静态构造函数是否可使用this?
(4)实现C#归并排序。
(5)写一个事件:饮水机没水时,A或B或其他人给它加水。
(6)“不要和陌生人说话”是设计模式中哪种原则的通俗表达?
(7)解释UML中的4个名词:依赖、聚合、泛化和关联。
(8)对象实现了Finalize将对垃圾收集有何影响?
(9)描述你对.NETFramework2.0中匿名方法的认识。
(10)1000瓶药水至多有l瓶含剧毒.给你10只狗,在24小时内通过给狗试药的方式找出哪瓶药水有毒或者全部无毒(狗服药X小时后毒发,19<X<23)。
面试例题1:编写一段代码,其功能是打印代码本身。(要完全使用程序代码生成一段和自己的代码一模一样的字符串)。[欧盟著名通讯公司N面试题,2008]
解析:一道很有趣的面试题,就好像要求一个魔术师,扯着头发把自己拔起来的感觉。本题在编写时要注意计算代码长度。答案:用C#编写代码如下:(仅一行)
class P { static void Main() { string s = "class P{{static void Main(){{string s=;System.Console.WriteLine(s,s,(char)34);}}}}"; System.Console.WriteLine(s, s, (char)34); } }
6.1【const】
面试例题1:const 和 static readonly 区别是什么?
解析:
这个问题虽然很简单,但有时候也能困扰我们。const和static readonly的确很像,都在程序中只读,都是一旦初始化则都不再可以改写,都是属于语言的静态。并且在多数情况下可以混用。
两者区别是这样的,关于const
1.在编译期间解析的常量;
2.必须在声明就初始化;
3.既可用来修饰类中的成员,也可修饰函数体内的局部变量。
而关于static readonly
1.在运行期间解析的常量;
2.既可以在声明时初始化,也可以在构造器中初始化;
3.只可以用于修饰类中的成员
这里有几个例子:
static readonly MyClass myclass = new MyClass();
//必须使用static readonly,因为new需要在运行时确定
//而const只能必须在编译时就确定
static readonly A = B * 20;
static readonly B = 10;
//可以使用static readonly,显然可以在运行时确定语句
//也可以使用const// const A = B * 20;
// const B = 10;
//编译器会在编译时候,就把B编译为10,A编译为200,而不是在运行时再计算B * 202.
下面有一个项目,有一个MyInt的属性,定义如下:
public class MYClass
{
public const int MyInt = 5;
public static readonly String strStaticReadonly = "StaticReadonly";
}
另一个项目中引用该属性
public class AnotherClass
{
int I = MYClass.MyInt;
string kk = MYClass.strStaticReadonly;
}
编译运行程序, I = 5;kk = StaticReadonly。这是当然的。但是如果我们改变MYClass中的MyInt和strStaticReadonly的值:
public class MYClass
{
public const int MyInt = ; //这里改为6
public static readonly String strStaticReadonly = "changed";//这里改为changed
}
然后编译MYClass所在的项目,生成dll。再运行程序AnotherClass(只是运行,而不是编译后运行),发现I还是= 5,而不是6!,但是strStaticReadonly却变成了changed。为什么会这样?因为在AnotherClass中,I已经被定义为5而不是运行时再去取dll的值,所以说const是编译时就唯一确定了。
答案:C#拥有两种不同的常量:静态常量(compile-time constants)和动态常量(runtime constants)。它们有不同的特性,错误的使用不仅会损失效率,还可能造成错误。相比之下,静态常量在速度上会稍稍快一些,但是灵活性却比动态常量差很多。
//静态常量(隐式是静态的)
public const int compiletimeConstant = 1;
//动态常量
public static readonly runtimeConstant = 1;
静态常量在编译时会将其替换为所对应的值,也就是说下面这2句话通过编译器编译后产生的中间语言是一样的。
//通过编译后二者会被翻译成相同的中间语言
int myNum = compiletimeConstant;
int myNum = 1;
动态常量的值是在运行时获得的。编译器将其标为只读常量,而不是用常量的值代替。静态常量只能被声明为简单的数据类型(内建的int和浮点型)、枚举或字符串。下面的程序段是通不过编译的。你不能用new关键字初始化一个静态常量,即便是对一个值类型来说。
//这样是错误的
public const DateTime myDateTime = new DateTime(2006,9,1,0,0,0);
//这样是可以的
public static readonly DateTime myDateTime = new DateTime(2006,9,1,0,0,0);
只读数据也是常量的一种,它们不能在构造器初始化之后被修改。但是它同静态常量不同,它的值是在运行时才被指派的,因此就会获得更大的灵活性。动态常量可以是任意的数据类型。二者最大的差别在于:静态常量在编译时会将其换为对应的值,这就意味着对于不同的程序集来说,当你改变静态常量的时候需要将其重新编译,否则常量的值不会发生变化,可能引发潜在的问题,而动态常量就不会有这种情况。用const定义的常量(隐式是静态的),需要像访问静态成员那样去访问const定义的常量,而用对象的成员方式去访问会出编译错误。声明的同时要设置常量值。从另一方面来说,如果你的确要声明一些从不改变且处处唯一的常量,例如钩子函数SetWindowsHookEx的idHook参数或序列化时的版本等,就应该使用静态常量。但是用到这样的常量的机会不多。一般来说我们应该使用灵活性更高的动态常量。
两者区别如下:
静态常量 动态常量
内存消耗 无 因为要保存常量 有消耗
初始化 很少的简单类型;不能new,必须在声明同时赋值 任意类型,可以在类构造函数中赋值
何时发挥作用 编译时进行替换 相当于类中的数据成员
11.2【事件】
面试例题1:写一个事件,公司饮水机没水时候,小王、小李或者公司其他同事给引水机加水?
解析:本题主要考校观察者模式,观察者模式中主要包括如下两类对象:
1. Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,饮水机就是一个监视对象,它包含的其他对象所感兴趣的内容,就是waterTankState字段,当这个字段的值为0的时候,会不断把数据发给监视它的对象。
2. Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer就是员工,它们采取的行动分别是Drink和FillWater。
在本题中,事情发生的顺序应该是这样的:
1. 员工告诉饮水机,它对它的容积比较感兴趣(注册)。
2. 饮水机知道后保留对员工的引用。
3. 员工到饮水机前进行饮水这一动作,当容积为0,通过引用,自动调用Fillwater()方法。
类似这样的例子是很多的,GOF对它进行了抽象,称为观察者模式:观察者模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。观察者模式是一种松耦合的设计模式。
答案: 详细代码如下:
// Observer pattern -- Structural example
using System;
//Delegate 加水委托
delegate void fillwaterDelegate();
//ConcreteWaterTank 创建水箱类
class ConcreteWaterTank
{
// Fields
private int subjectCubage; //当前容积
public event fillwaterDelegate fillwaterHandler; //建立加水事件
// Properties
public int waterTankCubage
{
get { return subjectCubage; }
set { subjectCubage = value; }
}
// Methods
public void Attach(fillwaterDelegate ud)
{
fillwaterHandler += ud;
}
public void Detach(fillwaterDelegate ud)
{
fillwaterHandler -= ud;
}
public void Notify()
{
if (fillwaterHandler != null) fillwaterHandler();
}
}
// "ConcreteEmployee" //建立员工类
class ConcreteEmployee
{
// Fields
private string employeeName; //员工姓名
private int observerCubage; //关注水箱状态
private ConcreteWaterTank subject;
// Constructors //建立构造函数
public ConcreteEmployee(ConcreteWaterTank subject,
string employeeName)
{
this.subject = subject;
this.employeeName = employeeName;
}
// Methods
public void fillWater()
{
if (subject.waterTankCubage == 0)
//关注水箱 如果水箱没水 则注水
{
Console.WriteLine("Employee go to waterTank and find the water is Null", employeeName);
subject.waterTankCubage = 10;
observerCubage = subject.waterTankCubage;
Console.WriteLine("Employee fill water to waterTank.Now waterTank's state is ", employeeName, observerCubage);
subject.waterTankCubage = subject.waterTankCubage - 1;
observerCubage = subject.waterTankCubage;
Console.WriteLine("After do that he drink, Now waterTank's state is ",employeeName, observerCubage);
}else
{
//否则 则饮水
subject.waterTankCubage = subject.waterTankCubage - 1;
observerCubage = subject.waterTankCubage;
Console.WriteLine("Employee go to waterTank, and he drink, Now waterTank's state is ",employeeName, observerCubage);
}
}
// Properties
public ConcreteWaterTank waterTank
{
get { return subject; }
set { subject = value; }
}
}
// "ConcreteEmployee" //其他观察者 他们仅是观察但不动作
class AnotherObserver
{
// Methods
public void Show()
{
Console.WriteLine("AnotherObserver got an Notification!");
}
}
public class Client
{
public static void Main(string[] args)
{
ConcreteWaterTank s = new ConcreteWaterTank ();
//建立水箱s
ConcreteEmployee o1 = new ConcreteEmployee(s, "ZhangSan");
ConcreteEmployee o2 = new ConcreteEmployee(s, "LiSi");
ConcreteEmployee o3 = new ConcreteEmployee(s, "WangEr");
ConcreteEmployee o4 = new ConcreteEmployee(s, "ZhaoLiu");
//建立员工对象 张三 李四 王二 赵六并绑定水箱s
AnotherObserver o5 = new AnotherObserver();
//建立普通观察者对象 o5
s.Attach(new fillwaterDelegate(o1.fillWater));
s.Attach(new fillwaterDelegate(o2.fillWater));
s.Attach(new fillwaterDelegate(o3.fillWater));
s.Attach(new fillwaterDelegate(o4.fillWater));
s.Attach(new fillwaterDelegate(o5.Show));
//绑定事件fillwaterHandler
s.waterTankCubage = 2;//水箱初始状态2升
s.Notify();//事件开始运行
Console.WriteLine("--------------------------");
s.Detach(new fillwaterDelegate(o1.fillWater));
//把o1也就是员工张三加水行为从事件中剥离
s.waterTankCubage = 1; //水箱初始状态1升
s.Notify();//事件开始运行
}
}
12.2【栈和堆】
面试例题1:编号为123456789的火车经过如下轨道从左边入口处移到右边出口处(每车都必须且只能进临时轨道M一次,且不能再回左边入口处) [中国台湾计算机硬件公司W面试题,2008.11]
-----------------------------------------------------
987654321
-------------------/ /-----------------------------
| |
| |
|M|
| |
|_|
按照从左向右的顺序,下面的结果不可能是______
A 123876549
B 321987654
C 321456798
D 987651234
解析:本题实际上考的是数据结构的栈。临时轨道M就是栈。
A 123挨个过去,45678入栈再出栈变成87654,9再过去;
B 123入栈再出栈变成321,456789入栈再出栈变成987654;
C 123入栈再出栈变成321,4567直接过去,89入栈再出栈变成98;
D 98765在前,则1234必须全部先进栈,98765过去后,剩下1234必须先回到左边,再通过才满足1234。但是题意要求不可再回到左边入口处,所以这个选项不可行。
答案:D
扩展知识:如果M只能容纳4列车。上面选项因该选哪个才可行?
16.2【性能测试】
面试例题1:在用户体验测试中,发现问题可能存在误测,误测包括两种:第1,问题被遗漏了;第2,不是问题却被认为是问题。我们的测试通常通过两种不同的测试方法来进行,他们依据完成不同的设计思路,但是有一些共同的:第1他们都能发现所有存在的问题;第2仍然会有百分之三的误测率;第3不会出现同一问题被对两个系统都误测的可能性。为了测试一个非常重要的系统,我们会把两个测试方法进行交叉测试,测试结果采取并集,我们可以这样推理:采用这种方法的时候是不会出现任何误测的情况。
以下哪项最恰当描述了上述推理?
A 上述推理是必然的,即如果前提为真,则结论一定真;
B 上述推理很强,但不是必然,即如果前提条件为真,则为结论提供很强的证明,但附加信息仍可削弱论证;
C 上述推理很弱,前提条件尽管与结论相关,但最多只为结论提供不充分证明;
D 推论不成立,因为他把某些必要的条件当作了充分的条件。
解析:因为从前提条件中只知道有两种误测,但并未说明两种误测能够在测试时就知道,因此当误测发生时,我们无法区分是哪种误测,因此即使使用两种测试方法进行交叉测试取并集,最多只能保证不被遗漏,但是不能解决不是问题却被认为是问题。
答案:D
第27章 智力测试
27.1【关于数字的智力问题】
面试例题3:1000瓶药水,其中至多有1瓶剧毒,现在给你10只小狗在24小时内通过小狗试药的方式找出哪瓶药有毒或者全部无毒(小狗服完药X小时后才会毒发。19<X<23)[中国著名互联网企业T面试题,2008年11月]
答案:按10进制方式给狗编号分别是1-10。按2进制方式给药水编号。按照药水第几位数字为1,给相应的狗服药。如下:
第1瓶 0000000001 第1位数字为1,给1号狗服药。
第2瓶 0000000010 第2位数字为1,给2号狗服药。
第3瓶 0000000011 第1、2位数字为1,给1、2号狗服药。
第4瓶 0000000100 第3位数字为1,给3号狗服药。
……
第99瓶 0001100011 第1、2、6、7位数字为1,给1、2、6、7号狗服药。
……
第455瓶 0111000111 第1、2、3、7、8、9位数字为1,给1、2、3、7、8、9号狗服药。
……
第1000瓶 1111101000 第4、6、7、8、9、10位数字为1,给4、6、7、8、9、10号狗服药。
最后看哪只狗毒发,则通过狗的编号得出药瓶号码。比如1、2、3、7、8、9号狗毒发,则455瓶(编号0111000111)为毒药。