精通C#编程、.NET体系;熟悉设计模式、数据结构的面

(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)为毒药。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值