1. C#中值类型和引用类型

(1) 值类型和引用类型分别有哪些?

值类型:结构体(数值类型,bool型,用户定义的结构体),枚举enum,可空类型。 引用类型:数组,用户定义的类、接口、委托,object,string

(2) c#中值类型和引用类型的区别

  1. 值类型的数据存储在内存的栈中;引用类型的数据存储在内存的堆中,而内存单元中只存放堆中对象的地址。
  2. 值类型存取速度快,引用类型存取速度慢。
  3. 值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针或引用
  4. 值类型继承自System.ValueType,引用类型继承自System.Object
  5. 栈的内存分配是自动释放;而堆在.NET中会有GC来释放
  6. 将一个值类型变量赋给另一个值类型变量时,将复制包含的值。引用类型变量的赋值只复制对对象的引用,而不复制对象本身。
  7. 值类型不可能派生出新的类型:所有的值类型均隐式派生自 System.ValueType。但与引用类型相同的是,结构也可以实现接口。
  8. 值类型不可能包含 null 值:然而,可空类型功能允许将 null 赋给值类型。
  9. 每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值。

(3) string为什么引用类型:

  1. String类型直接继承自Object;
  2. 空间使用大概率较大,如果字符串做成值类型,那么程序中各种字符串值复制会乱飞,小到几字,大到上百字,而栈空间有限,同时,复制几十字节方便还是复制地址方便?

(4) 为什么string是引用类型 值还不可以修改:

C#把数据类型分为值类型和引用类型。值类型操作简单,引用类型更省空间。 C#一共有15个预定义类型,其中13个值类型(8个整型、2个浮点类型、decimal、bool、char),2个引用类型(string、object)。 仔细看,值类型都是空间使用较小的类型,引用类型都是空间使用较大的类型(如string、我们自己声明的类)。(这里先不考虑作为值类型的结构) string 因为空间使用大概率较大,所以被作为引用类型。但是如果和一般的引用类型的赋值操作一样,那么容易被在不需要改动的情况下修改。 所以,微软给了折中的办法,每次值的变更,都会给出一个新的地址给变量。原来的地址还是原来的值,自己的修改不影响别人。 这样,string既有引用类型的空间节省,又有值类型的便捷。

2. 字段和属性有什么区别

C#面试题(一) - 图1

字段是类用public修饰符所公开的变量,属性是对字段的封装,属性的实质是方法{get;set;}方法 字段就是类内部用来存储数据,属性是类提供给外部调用时设置或读取一个值。 如果你编写一些控件给别的开发者用,而需要给他们提供“数据绑定”这种傻瓜化的机制,那么使用属性才可以做到。
属性是方法而字段不是,当你用反射去调用的时候,它们有各自的API。因为属性是方法,所以它可以和方法那样定义在接口中,或者被继承和重写,重写属性被ORM/AOP等框架用来注入代码。

总结:

  1. 访问性不同
属性:C#中属性是限制只能给变量赋于某个范围的值,是有限制的访问私有变量。 字段:C#中字段是自由的、毫无限制的访问公有变量。
  1. 包含不同
属性:C#中属性中包含两个块:set和get,set块负责属性的写入工作,get块负责属性的读取工作。 字段:C#中字段中不包含set和get两个块,可以直接进行字段写入和读取。
  1. 安全性不同
属性:C#中属性因为是私有的、写入和读取需要调用set和get块,所以当不在本类中使用时可以保证使用属性的安全性。 字段:C#中字段因为是公有的、写入和读取不需要调用set和get块,所以当不在本类中使用时无法保证使用字段的安全性。

3. 抽象方法和虚方法的区别

(1)抽象方法是只有方法名称,没有方法体(也就是没有方法具体实现),子类必须重写父类抽象方法 虚函数是该方法有方法体,但是子类可以覆盖,也可不覆盖。 (2)虚方法有方法体,抽象方法没有方法体。抽象方法是一种强制派生类覆盖的方法,否则派生类将不能被实例化; (3)抽象方法只能在抽象类中声明,虚方法不是; (4)派生类必须重写抽象类中的抽象方法,虚方法则不必要。 抽象方法一定是虚方法,虚方法未必是抽象方法。

1、抽象方法:只在抽象类中定义,方法修饰符不能使用private,virtual,static.

抽象方法如下示:
  1. public abstract class People //声明一个抽象类
  2. {
  3. public abstract void study(); //抽象方法只能定义在抽象类中。
  4. }
  5. public class Student : People //继承抽象类
  6. {
  7. public override void study() //重写抽象类的抽象方法
  8. {
  9. Console.WriteLine("好好学习,天天向上!");
  10. }
  11. }
  12. public class Program
  13. {
  14. static void Main(string[] args)
  15. {
  16. Student t= new Student();//实例化派生类
  17. People p= t; //使用派生类对象实例化抽象类
  18. //以上两句等价于 People p = new Student();//使用派生类对象实例化抽象类;
  19. p.study(); //使用抽象类对象调用抽象类中的抽象方法study
  20. }
  21. }
总结:(1)抽象方法只能声明在抽象类中,使用关键字abstract (2)抽象类中的抽象方法必须被子类重写。 【抽象方法没有方法体,子类必须重写方法体!!,因此抽象方法可以看成是一个没有方法体的虚方法】

2、虚方法:使用virtual修饰的方法:

虚方法可以有方法体。具体示例如下:
  1. public class BaseClass //创建一个基类
  2. {
  3. public virtual string GetName() //使用virtual关键字创建父类中的虚方法
  4. {
  5. return "父类虚方法体":
  6. }
  7. }
  8. public class SubClass : BaseClass //子类继承父类
  9. {
  10. public override string GetName(); //子类重写父类虚方法
  11. {
  12. return "重写父类虚方法!";
  13. }
  14. }
以上的示例:父类中的虚方法被派生类重写了。 注意事项:virtual修饰符不能与private、static、abstract、override修饰符同时使用。
用 static 修饰符声明属于类型本身而不是属于特定对象的静态成员。static 修饰符可用于类、字段、方法、属性、运算符、事件和构造函数, 但不能用于索引器、析构函数或类以外的类型。 常数或者类型声明隐式地是静态成员。不能通过实例引用静态成员。然而,可以通过类型名称引用它。 尽管类的实例包含该类所有实例字段的单独副本,但每个静态字段只有一个副本。 不可以使用 this 来引用静态方法或属性访问器。 如果对类应用 static 关键字,则该类的所有成员都必须是静态的。 类(包括静态类)可以有静态构造函数。在程序开始和实例化类之间的某个时刻调用静态构造函数。
ps:override修饰符不能与new 、static、virtual修饰符同时使用,并且重写方法只能用于重写基类中的虚方法。 虚函数的限制:
  • 虚函数仅适用于有继承关系的类对象,所以只有类的成员函数才能说明为虚函数;
  • 静态成员函数、内联函数、构造函数不能是虚函数;
  • 析构函数可以是虚函数。
虚函数的实现: 如果一个类的内部有虚函数,那么编译器会在类的内部添加一个虚拟函数表指针(vptr),这个vptr指向一个虚拟函数表,表中存放着该类所有虚拟函数的入口地址,在每一次虚函数调用时,会去这个表中查找地址。 多态的两种形式: 1、 静态多态(编译阶段) 包括函数重载和泛型编程。 在编译时就可以确定使用的接口。 2、 动态多态(运行阶段) 包括虚函数。 具体引用的接口在运行时才能确定

C#面试题(一) - 图2

  1. 构造函数为什么不能是虚函数
① vptr存放在对象的内部空间,需要构造函数来完成初始化。但如果构造函数是虚函数,那么调用构造函数则需要去寻找vptr,但此时vptr还未初始化,无法调用构造函数。 构造函数的作用是用来进行对象的初始化,在对象的生命期内仅运行一次,不是对象的动态行为,没必要成为虚函数
  1. 析构函数为什么常常是虚函数
析构函数 在某个对象被注销时,编译器会自动顺序调用该类极其父类的析构函数,而不会调用派生类的析构函数。
  1. fatherClass *p = new sonClass(); //用父类指针指向子类对象时
  2. delete p;
当调用基类的析构函数时: ① 若基类的析构函数未声明为虚函数,那么只会释放基类的内存,而不会释放派生类的内存(内存泄漏) ② 若基类的析构函数声明为虚函数,那么基类(fatherClass)内存中的vptr指向的是子类(sonClass)的虚函数表(子类的vptr浅拷贝到父类中),即可以通过父类的指针来调用子类的析构函数,从而在释放内存的时候,可以销毁子类,不会产生内存泄漏

所以,基类的析构函数一定要声明为虚函数(virtual)。

  1. 类的静态成员函数为什么不能是虚函数

因为静态成员函数是该类公用的,与类的对象无关,所以不能为虚函数。

静态成员函数

类的静态成员函数有如下特性:

  • 静态成员函数是类的一个特殊的成员函数
  • 静态成员函数属于整个类所有,没有this指针
  • 静态成员函数只能直接访问静态成员变量和静态成员函数
  • 可以通过类名直接访问类的公有静态成员函数
  • 可以通过对象名访问类的公有静态成员函数
  • 定义静态成员函数,直接使用static关键字修饰即可

静态成员和非静态成员的区别

  • 1.静态成员用statis修饰符声明,在类被实例化时创建,通过类进行访问
  • 2.不带statis的变量时非静态变量,在对象被实例化时创建,通过对象进行访问,
  • 3.静态方法里不能使用非静态成员,非静态方法可以使用静态成员
  • 4.静态成员属于类,而不属于对象

C#面试题(一) - 图3

  1. 内联函数为什么不能是虚函数

因为内联函数需要在编译阶段展开,而虚函数则是为了实现多态,在运行阶段动态绑定的。

(3) 在什么情况下会用到虚方法?它与接口有什么不同?

子类重新定义父类的某一个方法时,必须把父类的方法定义为virtual

在定义接口中不能有方法体,虚方法可以。

实现时,子类可以不重新定义虚方法,但如果一个类继承接口,那必须实现这个接口。

4. 什么是虚函数?什么是抽象函数?

虚函数:没有实现的,可由子类继承并重写的函数。

抽象函数:规定其非虚子类必须实现的函数,必须被重写。

5. using关键字有什么用?什么是IDisposable?

using可以声明namespace的引入,还可以实现非托管资源的释放,实现了IDisposiable的类在using中创建,using结束后会自动调用该对象的Dispose方法,释放资源。

加分的补充回答:using其实等价于try……finally,用起来更方便。
  1. 引用命名空间,也可using 别名
  2. 释放资源,实现了IDisposiable的类在using中创建,using结束后会自定调用该对象的Dispose方法,释放资源。

6. new的几种用法

三种用法如下:

在 C# 中,new 关键字可用作运算符、修饰符或约束。

1)new 运算符:用于创建对象和调用构造函数。

1.用于创建对象和调用构造函数 例:Class_Test MyClass = new Class_Test(); 2.也用于为值类型调用默认的构造函数 例:int myInt = new int(); myInt 初始化为 0,它是 int 类型的默认值。该语句的效果等同于:int myInt = 0; 3.不能重载 new 运算符。 4.如果 new 运算符分配内存失败,则它将引发 OutOfMemoryException 异常。

2)new 修饰符:在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。

3)new 约束:用于在泛型声明中约束可能用作类型参数的参数的类型。

关于第二种用法看下例:
  1. using System;
  2. namespace ConsoleApplication1
  3. {
  4. public class BaseA
  5. {
  6. public int x = 1;
  7. public void Invoke()
  8. {
  9. Console.WriteLine(x.ToString());
  10. }
  11. public int TrueValue
  12. {
  13. get { return x; }
  14. set { x = value; }
  15. }
  16. }
  17. public class DerivedB : BaseA
  18. {
  19. new public int x = 2;
  20. new public void Invoke()
  21. {
  22. Console.WriteLine(x.ToString());
  23. }
  24. new public int TrueValue
  25. {
  26. get { return x; }
  27. set { x = value; }
  28. }
  29. }
  30. class Test
  31. {
  32. static void Main(string[] args)
  33. {
  34. DerivedB b = new DerivedB();
  35. b.Invoke();//调用DerivedB的Invoke方法,输出:2
  36. Console.WriteLine(b.x.ToString());//输出DerivedB的成员x值:2
  37. BaseA a = b;
  38. a.Invoke();//调用BaseA的Invoke方法,输出:1
  39. a.TrueValue = 3;//调用BaseA的属性TrueValue,修改BaseA的成员x的值
  40. Console.WriteLine(a.x.ToString());//输出BaseA的成员x的值:3
  41. Console.WriteLine(b.TrueValue.ToString());//输出DerivedB的成员x的值,仍然是:1
  42. //可见,要想访问被隐藏的基类的成员变量、属性或方法,办法就是将子类造型为父类,然后通过基类访问被隐藏的成员变量、属性或方法。
  43. }
  44. }
  45. }

new约束指定泛型类声明中的任何类型参数都必须具有公共的无参数构造函数.请看下例:

  1. using System;
  2. using System.Collections.Generic;
  3. namespace ConsoleApplication2
  4. {
  5. public class Employee
  6. {
  7. private string name;
  8. private int id;
  9. public Employee()
  10. {
  11. name = "Temp";
  12. id = 0;
  13. }
  14. public Employee(string s, int i)
  15. {
  16. name = s;
  17. id = i;
  18. }
  19. public string Name
  20. {
  21. get { return name; }
  22. set { name = value; }
  23. }
  24. public int ID
  25. {
  26. get { return id; }
  27. set { id = value; }
  28. }
  29. }
  30. class ItemFactory<T> where T : new()
  31. {
  32. public T GetNewItem()
  33. {
  34. return new T();
  35. }
  36. }
  37. public class Test
  38. {
  39. public static void Main()
  40. {
  41. ItemFactory<Employee> EmployeeFactory = new ItemFactory<Employee>();
  42. ////此处编译器会检查Employee是否具有公有的无参构造函数。
  43. //若没有则会有The Employee must have a public parameterless constructor 错误。
  44. Console.WriteLine("{0}'ID is {1}.", EmployeeFactory.GetNewItem().Name, EmployeeFactory.GetNewItem().ID);
  45. }
  46. }
  47. }
除了作为创建对象实例的关键字以外,new还有个罕见的用法,就是在派生类定义一个重名的同函数签名的方法,隐藏掉基类的方法。另外就是泛型约束定义构造函数约束的时候用。

new 修饰符(C# 参考)

在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。隐藏继承的成员意味着该成员的派生版本将替换基类版本。在不使用 new 修饰符的情况下隐藏成员是允许的,但会生成警告。使用 new 显式隐藏成员会取消此警告,并记录代之以派生版本这一事实。 若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并使用 new 修饰符修饰该成员

new 运算符(C# 参考)

1.用于创建对象和调用构造函数。例如:

Class1 o = new Class1();

2.也用于为值类型调用默认的构造函数

例:int myInt = new int(); myInt 初始化为 0,它是 int 类型的默认值。该语句的效果等同于:int myInt = 0;

3.不能重载 new 运算符。

4.如果 new 运算符分配内存失败,则它将引发 OutOfMemoryException 异常

new 约束(C# 参考)

new 约束指定泛型类声明中的任何类型参数都必须有公共的无参数构造函数。当泛型类创建类型的新实例时,将此约束应用于类型参数,如下面的示例所示:
  1. class ItemFactory<T> where T : new()
  2. {
  3. public T GetNewItem()
  4. {
  5. return new T();
  6. }
  7. }
通过继承隐藏名称采用下列形式之一: 1.引入类或结构中的常数、指定、属性或类型隐藏具有相同名称的所有基类成员。 2.引入类或结构中的方法隐藏基类中具有相同名称的属性、字段和类型。同时也隐藏具有相同签名的所有基类方法。 3.引入类或结构中的索引器将隐藏具有相同名称的所有基类索引器。 4.在同一成员上同时使用 new 和 override 是错误的。 注意:在不隐藏继承成员的声明中使用 new 修饰符将生成警告。 示例 在该例中,嵌套类 MyClass 隐藏了基类中具有相同名称的类。该例不仅说明了如何使用完全限定名访问隐藏类成员,同时也说明了如何使用 new 修饰符消除警告消息。
  1. using System;
  2. public class MyBaseC
  3. {
  4. public class MyClass
  5. {
  6. public int x = 200;
  7. public int y;
  8. }
  9. }
  10. public class MyDerivedC : MyBaseC
  11. {
  12. new public class MyClass // nested type hiding the base type members
  13. {
  14. public int x = 100;
  15. public int y;
  16. public int z;
  17. }
  18. public static void Main()
  19. {
  20. // Creating object from the overlapping class:
  21. MyClass S1 = new MyClass();
  22. // Creating object from the hidden class:
  23. MyBaseC.MyClass S2 = new MyBaseC.MyClass();
  24. Console.WriteLine(S1.x);
  25. Console.WriteLine(S2.x);
  26. }
  27. }
  28. //输出
  29. //100
  30. //200

7. 什么叫做泛型

从编程的角度说,是在定义类或者方法的时候省去具体的类型,由调用者来指定,类型+泛型类型合成得到真正的类型。 从实现机制上说,泛型是CLR在运行时动态根据泛型类型创建的匿名类型。 从OO设计的角度说,泛型体现了多态性。泛型使得程序员可以复用数据结构和算法,并且适应不同的类型,享有编译期间的强类型检查和语法提示。
一些经典的FCL提供的泛型类型和接口: List、Dictionary这个属于复用数据结构 IComparer、IEnumerable这个属于复用算法

8. 接口和类

(1) 什么叫做类

就C#而言,类是对象的模板,对象是类的实例。C#是强类型语言,一切皆需要类型,除了内置的简单类型,那些其实例为引用对象的都叫做类。C#也允许定义抽象类和密封类,以及两者的叠加——静态类,它们都无法实例化,其实这是编译器的限制,本质上它们和一般的类没有区别,是特殊情况。

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

  • 不同点:

不能直接实例化接口。

接口不包含方法的实现。

接口可以多继承,类只能单继承。

类定义可在不同的源文件之间进行拆分。

  • 相同点:

接口、类和结构都可以从多个接口继承。

接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员。

接口和类都可以包含事件、索引器、方法和属性。

基础知识:接口只能定义方法(只能定义行为,不能定义实现也就是字段),因为事件、索引器、属性本质上都是方法,所以接口中也可以定义事件、索引器、属性。

简单说来,所谓索引器就是一类特殊的属性,通过它们你就可以像引用数组一样引用自己的类。

(3) 说出一些常用的类、接口,请各举5个

要让人家感觉你对.Net开发很熟,所以,不能仅仅只列谁都能想到的那些东西,要多列你在做项目中涉及的那些东西。就写你最近写的那些程序中涉及的那些类。

常用的类:StreamReader、WebClient、Dictionary、StringBuilder、SqlConnection、FileStream、File、Regex、List

常用的接口:IDisposable、IEnumerable、IDbConnection、IComparable、ICollection、IList、IDictionary

(4) 接口可以包含哪些成员?

接口可以包含属性、方法、索引指示器和事件,但不能包含常量、域、操作符、构造函数和析构函数,而且也不能包含任何静态成员

9. 继承与实现

(1) 接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?

接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承实体类,但前提是实体类必须有明确的构造函数。具体可看Java笔记—继承与实现。

(2) 是否可以继承String类?

String类是final类(或者sealed类)故不可以继承。

(3) List,Set, Map是否继承自Collection接口?

List,Set是Map不是

(4) 用sealed修饰的类有什么特点?

密封,不能继承。

sealed修饰符有什么特点

sealed 修饰符可以应用于类、实例方法和属性。

密封类不能被继承;

密封方法会重写基类中的方法,但其本身不能在任何派生类中进一步重写。当应用于方法或属性时,sealed 修饰符必须始终与 override一起使用。

(5) C#支持多重继承么?

类之间不支持,接口之间支持。类对接口叫做实现,不叫继承。 类是爹、接口是能力,能有多个能力,但不能有多个爹。

(6) 在.Net中,类System.Web.UI.Page 可以被继承么?

可以。

10.重写与重载

(1) 重写与重载的区别

重载是方法的名称相同。参数或参数类型不同,进行多次重载以适应不同的需要.

Override是进行基类中函数的重写。为了适应需要。(在Java中子类必须要重写基类的抽象方法,非抽象方法可以有开发者选择是否重写)

(2) 构造器Constructor是否可被override?

构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading。

(3) 利用operator声明且仅声明了==,有什么错误么?

要同时修改Equale和GetHash() ? 重载了”==” 就必须重载 “!=”

(4) 重载与覆盖的区别?

1、方法的覆盖是子类和父类之间的关系,是垂直关系;方法的重载是同一个类中方法之间的关系,是水平关系。 2、覆盖只能由一个方法,或只能由一对方法产生关系;方法的重载是多个方法之间的关系。 3、覆盖要求参数列表相同;重载要求参数列表不同。 4、覆盖关系中,调用那个方法体,是根据对象的类型(对像对应存储空间类型)来决定;重载关系,是根据调用时的实参表与形参表来选择方法体的。

(5) Overloaded的方法是否可以改变返回值的类型?

Overloaded的方法是可以改变返回值的类型。

11. 进程和线程

(1) 进程和线程的区别?

进程是系统进行资源分配和调度的单位;

线程是CPU调度和分派的单位,一个进程可以有多个线程,这些线程共享这个进程的资源。

(2) 启动一个线程是用run()还是start()?

启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。 run()方法可以产生必须退出的标志来停止一个线程。

(3) 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?

不能,一个对象的一个synchronized方法只能由一个线程访问。

12. C#语言中,结构体和类的区别?

  1. 结构是实值类型(Value Types),而类则是引用类型(Reference Types)。
  2. 结构使用栈存储(Stack Allocation),而类使用堆存储(Heap Allocation)。
  3. 所有结构成员默认都是Public,而类的变量和常量数则默认位Private,不过其他类成员默认都是Public。
  4. 结构成员不能被声明位Protected,而类成员可以。
结构与类共享几乎所有相同的语法,但结构比类受到的限制更多:尽管结构的静态字段可以初始化,结构实例字段声明还是不能使用初始值设定项。 结构不能声明默认构造函数(没有参数的构造函数)或析构函数。 结构的副本由编译器自动创建和销毁,因此不需要使用默认构造函数和析构函数。实际上,编译器通过为所有字段赋予默认值(参见默认值表)来实现默认构造函数。 结构不能从类或其他结构继承。 结构是值类型 — 如果从结构创建一个对象并将该对象赋给某个变量,变量则包含结构的全部值。复制包含结构的变量时,将复制所有数据,对新副本所做的任何修改都不会改变旧副本的数据。 由于结构不使用引用,因此结构没有标识 — 具有相同数据的两个值类型实例是无法区分的。C# 中的所有值类型本质上都继承自ValueType,后者继承自 Object。编译器可以在一个称为装箱的过程中将值类型转换为引用类型。 结构具有以下特点: 结构是值类型,而类是引用类型。 向方法传递结构时,结构是通过传值方式传递的,而不是作为引用传递的。 与类不同,结构的实例化可以不使用 new 运算符。 结构可以声明构造函数,但它们必须带参数。 一个结构不能从另一个结构或类继承,而且不能作为一个类的基。所有结构都直接继承自 System.ValueType,后者继承自 System.Object。 结构可以实现接口。 在结构中初始化实例字段是错误的。

13. BS与CS

(1) BS与CS的联系与区别。

  1. C/S是客户端需要安装专用的客户端软件,B/S是客户机上只要安装一个浏览器
  2. C/S 一般建立在专用的网络上,C/S更强的适应范围,
  3. C/S比B/S更安全。
  4. C/S可以控制本机的其他程序、可以读写本地磁盘文件、可以与硬件交互。
  5. B/S很难和本地硬件、程序、文件进行交互

(2) 如果在一个B/S结构的系统中需要传递变量值,但是又不能使用Session、Cookie、Application,您有几种方法进行处理?

this.Server.Transfer

14. post与get

(1) post、get的区别

  1. post的参数不会显示在浏览器地址栏中,get的参数会显示在浏览器地址栏中
  2. 用post可提交较大的数据量,get提交的数据量则非常小(2k),受限于网页地址的长度。
  3. 用post可进行文件的提交,而用get则不可以。使用post提交的页面在点击【刷新】按钮的时候浏览器一般会提示“是否重新提交”,而get则不会;
  4. 用get的页面可以被搜索引擎抓取,而用post的则不可以;

参考阅读:http://www.cnblogs.com/skynet/archive/2010/05/18/1738301.html

(2) 向服务器发送请求有几种方式?

get,post。get一般为链接方式,post一般为按钮方式

15. try{}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

会执行,在return前执行。

16. 堆和栈的区别?

堆:编译期间就分配好的内存空间,因此你的代码中必须就栈的大小有明确的定义;局部值类型变量、值类型参数等都在栈内存中。一般由程序员分配释放。用new、malloc等分配内存函数分配得到的就是在堆上 栈:程序运行期间动态分配的内存空间,你可以根据程序的运行情况确定要分配的堆内存的大小。由编译器自动分配、释放。在函数体中定义的变量通常在栈上。 具体可见Java笔记—堆和栈。

1.申请方式的不同。栈由系统自动分配,而堆是人为申请开辟;

2.申请大小的不同。栈获得的空间较小,而堆获得的空间较大;

3.申请效率的不同。栈由系统自动分配,速度较快,而堆一般速度比较慢;

4.存储内容的不同。栈在函数调用时,函数调用语句的下一条可执行语句的地址第一个进栈,然后函数的各个参数进栈,其中静态变量是不入栈的。而堆一般是在头部用一个字节存放堆的大小,堆中的具体内容是人为安排;

5.底层不同。栈是连续的空间,而堆是不连续的空间。

17. StringBuilder 和 String

(1) StringBuilder 和 String 的区别?

  1. StringBuilder 是可扩展的,在大量字符串拼接时使用
  2. String 在进行运算时(如赋值、拼接等)会产生一个新的实例,而 StringBuilder 则不会。所以在大量字符串拼接或频繁对某一字符串进行操作时最好使用 StringBuilder,不要使用 String。
  3. 如果要操作一个不断增长的字符串,尽量不用String类,改用StringBuilder类。两个类的工作原理不同:String类是一种传统的修改字符串的方式,它确实可以完成把一个字符串添加到另一个字符串上的工作没错,但是在.NET框架下,这个操作实在是划不来。因为系统先是把两个字符串写入内存,接着删除原来的String对象,然后创建一个String对象,并读取内存中的数据赋给该对象。这一来二去的,耗了不少时间。而使用System.Text命名空间下面的StringBuilder类就不是这样了,它提供的Append方法,能够在已有对象的原地进行字符串的修改,简单而且直接。当然,一般情况下觉察不到这二者效率的差异,但如果你要对某个字符串进行大量的添加操作,那么StringBuilder类所耗费的时间和String类简直不是一个数量级的。
  • 都是引用类型,分配再堆上
  • StringBuilder默认容量是16,可以允许扩充它所封装的字符串中字符的数量.每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量。
  • 对于简单的字符串连接操作,在性能上stringbuilder不一定总是优于strin因为stringbulider对象的创建也消耗大量的性能,在字符串连接比较少的情况下,过度滥用stringbuilder会导致性能的浪费而非节约,只有大量无法预知次数的字符串操作才考虑stringbuilder的使用。从最后分析可以看出如果是相对较少的字符串拼接根本看不出太大差别。
  • Stringbulider的使用,最好制定合适的容量值,否则优于默认值容量不足而频繁的进行内存分配操作,是不妥的实现方法。 参考链接:https://www.cnblogs.com/haofuqi/p/4826262.html

(2) string str = null 与 string str = “” 请尽量使用文字或图象说明其中的区别。

string str = null 是不给他分配内存空间,而string str = “” 给它分配长度为空字符串的内存空间。 string str = null没有string对象,string str =””有一个字符串对象。

  1. //反编译发现,string.Empty就是在类构造函数中 Empty = "";
  2. string s3 = string.Empty;

string.Empty相当于””,Empty是一个静态只读的字段。

(3) Strings = new String(“xyz”);创建了几个String Object?

两个对象,一个是“xyz”,一个是指向“xyz”的引用对象s。

(4) 不是说字符串是不可变的吗?string s=”abc”;s=”123”不就是变了吗?

String是不可变的在这段代码中,s原先指向一个String对象,内容是 “abc”,然后我们将s指向”123”,那么s所指向的那个对象是否发生了改变呢?答案是没有。这时,s不指向原来那个对象了,而指向了另一个 String对象,内容为”123”,原来那个对象还存在于内存之中,只是s这个引用变量不再指向它了。

18.

19. C#中的委托是什么?事件是不是一种委托?

委托是一种特殊的引用类型,将方法作为参数进行传递。

使用过程的步骤:类型定义,对象创建,绑定方法,方法调用

委托是一种引用方法类型,一旦分配了方法,它将与该方法具有完全相同的行为。委托方法的使用可以跟其他任何方法一样,具有返回值和参数。委托可以看作是对函数的抽象,是函数的“类”,委托的实例代表一个具体的函数。

委托本质上是一种“方法接口”,它相当于C/C++中的函数指针,当然它比函数指针安全,在C#中通常用于事件处理。委托可以把一个方法作为参数代入另一个方法;委托可以理解为指向一个函数的引用。

  • 事件是一种特殊的委托。
  • 事件不是委托,不过由于事件的性质决定了处理它的程序逻辑能访问的参数,因此,在C#中处理事件的逻辑都包装为委托。
  • 委托和事件没有可比性,因为委托是类型,事件是对象,下面说的是委托的对象(用委托方式实现的事件)和(标准的event方式实现)事件的区别。事件的内部是用委托实现的。因为对于事件来讲,外部只能“注册自己+=、注销自己-=”,外界不可以注销其他的注册者,外界不可以主动触发事件,因此如果用Delegate就没法进行上面的控制,因此诞生了事件这种语法。事件是用来阉割委托实例的,类比用一个自定义类阉割List。事件只能add、remove自己,不能赋值。事件只能+=、-=,不能= 。加分的补充回答:事件内部就是一个private的委托和add、remove两个方法.

面试聊:用Reflector查看.Net的类的内部实现,解决问题。

详情可见C#事件与委托。

委托是一种方法容器,里面可以装载若干个方法引用地址,调用委托,就相当于同时调用了该容器内的所有方法。 委托可以将方法作为参数传递给方法.委托主要用来动态调用方法的。事件基于委托,事件的本质是委托字段的包装器,对委托字段的访问起限制作用,

事件隐藏了委托实例的大部分功能,仅暴露添加和移除事件处理器的功能。

请写出.net中两种常用内置委托以及它们的异同?

Func和Action,

Func委托必须有且只有一个返回值

Action泛型委托没有返回值,只能带入参数

20. 关键字区分

(1) 简述 private、 protected、 public、internal 修饰符的访问权限。

private : 私有成员, 在类的内部才可以访问。

protected: 保护成员,该类内部和继承类中可以访问。

internal:当前程序集内可以访问,在同一命名空间内可以访问。

public: 公共成员,完全公开,没有访问限制。

(2) 谈谈final,finally, finalize的区别。

  • final—修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中 不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为 final的方法也同样只能使用,不能重载。
  • finally—在异常处理时提供finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会 执行,然后控制就会进入 finally 块(如果有的话)。
  • finalize—方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的 ,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。

(3) C#中 property 与 attribute的区别,他们各有什么用处,这种机制的好处在哪里?

attribute:自定义属性的基类;

property :类中的属性

(4) abstract class和interface有什么区别?

  • 声明方法的存在而不去实现它的类被叫做抽像类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽像类,并让它指向具体子类的一个实例。不能有抽像构造函数或抽像静态方法。Abstract 类的子类为它们父类中的所有抽像方法提供实现,否则它们也是抽像类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。
  • 接口(interface)是抽像类的变体。在接口中,所有方法都是抽像的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽像的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对像上调用接口的方法。由于有抽像类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口。

相同点:

都不能被直接实例化,都可以通过继承实现其抽象方法。

不同点:

接口支持多继承;抽象类不能实现多继承。

接口只能定义行为;抽象类既可以定义行为,还可能提供实现。

接口只包含方法(Method)、属性(Property)、索引器(Index)、事件(Event)的签名,但不能定义字段和包含实现的方法;

抽象类可以定义字段、属性、包含有实现的方法。

接口可以作用于值类型(Struct)和引用类型(Class);抽象类只能作用于引用类型。例如,Struct就可以继承接口,而不能继承类。

加分的补充回答:讲设计模式的时候SettingsProvider的例子。

(5) Error和Exception有是区别?

error表示恢复不是不可能,但是很困难,exception表示一种实际或实现问题,它表示程序运行正常不可以发生的。

(6) HashMap和Hashtable区别?

HashMap是Hashtable的轻量级实现,非线程安全的实现他们都实现了map接口,主要区别是HashMap键值可以为空null,效率可以高于Hashtable。

(7) Collection和Collections的区别?

Collection是集合类的上级接口,Collections是针对集合类的一个帮助类,它提供一系列静态方法来实现对各种集合的搜索,排序,线程安全化操作。

(8) Const和ReadOnly?

Const用来申明编程时常量,ReadOnly用来申明运行时常量。

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

不是。可以用任意类型。

索引器(Indexer)是C#引入的一个新型的类成员,使对象可以像数组那样被方便,直观的引用。索引器可以有参数列表,只能作用在实例对象上,不能在类上直接作用。下面是典型的索引器的设计:
  1. class MyClass{
  2. public object this [int index]{
  3. get{
  4. // 取数据
  5. }
  6. set{
  7. // 存数据
  8. }
  9. }
  10. }
注意:这里的属性名是this,意思是回引类的当前实例,参数列表包含在方括号而非括号之内。索引器参数可以采用任何类型,int是通常最为合理的类型。同一类中还可能拥有一个以上的索引器(重载)。参考:C#中索引器的实现过程 ### 22. 装箱和拆箱 #### (1) 什么是装箱和拆箱? + 装箱:从值类型转换到引用类型,如: plain int i=0; Syste.Object obj=i; + 拆箱:就是将引用类型转换成值类型,如: plain int i=0; System.Object obj=i; int j=(int)obj;(将obj拆箱) Object是引用类型,但是它的子类Int32竟然不能去Object能去的“要求必须是引用类型”的地方,违反了继承的原则,所以需要把Int32装在Object中才能传递。 csharp object obj = null;//引用类型 obj = 1;//装箱,boxing。把值类型包装为引用类型。 int i1 = (int)obj;//拆箱。unboxing #### (2)下面三句代码有没有错,以inboxing或者unboxing为例,解释一下内存是怎么变化的 csharp int i=10; object obj = i; int j = obj; 分析:在inboxing(装箱)时是不需要显式的类型转换的,不过unboxing(拆箱)需要显式的类型转换,所以第三行代码应该改为: csharp int j = (int)obj; #### (3) 要掌握装箱与拆箱,就必须了解CTS及它的特点: NET重要技术和基础之一的CTS(Common Type System)。CTS是为了实现在应用程序声明和使用这些类型时必须遵循的规则而存在的通用类型系统。.Net将整个系统的类型分成两大类 :值类型和引用类型。 CTS中的所有东西都是对象;所有的对象都源自一个基类——System.Object类型值类型的一个最大的特点是它们不能为null,值类型的变量总有一个值。为了解决值类型不可以为null,引用类型可以为null的问题,微软在.Net中引入了装箱和拆箱:装箱就是将值类型用引用类型包装起来转换为引用类型;而从引用类型中拿到被包装的值类型数据进行拆箱。 ### 23. 托管代码 #### (1) 什么是托管代码、非托管代码 托管代码 (managed code) 由公共语言运行库环境(而不是直接由操作系统)执行的代码。托管代码应用程序可以获得公共语言运行库服务,例如自动垃圾回收、运行库类型检查和安全支持等。这些服务帮助提供独立于平台和语言的、统一的托管代码应用程序行为。 非托管代码 (unmanaged code) 在公共语言运行库环境的外部,由操作系统直接执行的代码。非托管代码必须提供自己的垃圾回收、类型检查、安全支持等服务;它与托管代码不同,后者从公共语言运行库中获得这些服务。 #### (2) 什么是受管制的代码? unsafe:非托管代码,不经过CLR运行。 ### 24. 什么是强类型系统? RTTI:类型识别系统。 ### 25. sleep()和 wait() 有什么区别? sleep()方法是使线程停止一段时间的方法。在sleep 时间间隔期满后,线程不一定立即恢复执行。这是因为在那个时刻,其它线程可能正在运行而且没有被调度为放弃执行,除非 + “醒来”的线程具有更高的优先级 + 正在运行的线程因为其它原因而阻塞。 wait()是线程交互时,如果线程对一个同步对象x 发出一个wait()调用,该线程会暂停执行,被调对象进入等待状态,直到被唤醒或等待时间到。 > ①. sleep是线程类Thread 的方法,它是使当前线程暂时睡眠,可以放在任何位置。 > > 而wait是Object类的方法,它是使当前线程暂时放弃对象的使用权进行等待,必须放在同步方法或同步块里。 > > ②. Sleep使用的时候,线程并不会放弃对象的使用权,即不会释放对象锁,所以在同步方法或同步块中使用sleep,一个线程访问时,其他的线程也是无法访问的。 > > 而wait是会释放对象锁的,就是当前线程放弃对象的使用权,让其他的线程可以访问。 > > ③. 线程执行wait方法时,需要另一个线程调用notify进行唤醒。 > > 而sleep只是暂时休眠一定时间,时间到了之后,自动恢复运行,不需另外的线程唤醒。 > ### 26. 编程填空题 #### (1) 面向对象的语言具有__性、_性、__性 封装、继承、多态。 #### (2) 能用foreach遍历访问的对象需要实现 __接口或声明__方法的类型。 IEnumerable 、 GetEnumerator。 #### (3) 在Asp.net中所有的自定义用户控件都必须继承自__? Control。 #### (4) 在.Net中所有可序列化的类都被标记为_? [serializable] #### (5) 在.Net托管代码中我们不用担心内存漏洞,这是因为有了__? GC。 #### (6) 类成员有_种可访问形式? this. new Class().Method #### (7) 当类T只声明了私有实例构造函数时,则在T的程序文本外部,可以(可以 or 不可以)从T派生出新的类,不可以(可以 or 不可以)直接创建T的任何实例。 不可以,不可以。 #### (8) 接口是一种引用类型,在接口中可以声明,但不可以声明公有的域或私有的成员变量。
方法、属性、索引器和事件;
解读:接口中不能声明字段只能声明方法,属性、索引器和事件 最终都编译生成方法。因为字段属于实现层面的东西,只有存取值的时候才会用到字段,所以中接口中不能定义字段。 #### (9) float f=-123.567F; int i=(int)f;i的值现在是_? -123。

(10) 委托声明的关键字是__?

delegate

27. 两个对象值相同(x.equals(y)== true),但却可有不同的hash code,这句话对不对?

不对,有相同的hash code。

28. swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?

switch(expr1)中,expr1是一个整数表达式。因此传递给 switch 和case语句的参数应该是 int、 short、 char 、byte、long、string。

29. abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?

都不能。

30. Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()?它们有何区别?

Set里的元素是不能重复的,那么用iterator()方法来区分重复与否。

equals()是判读两个Set是否相等。

equals()和==方法决定引用值是否指向同一对象

equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。

31. 数组有没有length()这个方法? String有没有length()这个方法?

数组没有length()这个方法,有length的属性。

String有有length()这个方法。

32. session和cookis

(1) Session有什么重大BUG,微软提出了什么方法加以解决?

iis中由于有进程回收机制,系统繁忙的话Session会丢失,可以用Sateserver或SQL Server数据库的方式存储Session

不过这种方式比较慢,而且无法捕获Session的END事件。

(2) session喜欢丢值且占内存,Cookis不安全,请问用什么办法代替这两种原始的方法

用ViewState,stateserver

33. 成员变量和成员函数前加static的作用?

它们被称为常成员变量和常成员函数,又称为类成员变量和类成员函数。分别用来反映类的状态。比如类成员变量可以用来统计类实例的数量,类成员函数负责这种统计的动作。

34. 请指出GAC的含义?

全局程序集缓存。

35. 在c#中using和new这两个关键字有什么意义,请写出你所知道的意义?using指令 和语句 new 创建实例 new 隐藏基类中方法。

using 引入名称空间或者使用非托管资源

new新建实例或者隐藏父类方法

36. 概述反射和序列化

反射

动态获取程序集信息。具体可见Java笔记—反射。公共语言运行库加载器管理应用程序域。这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。

在c#中,反射是什么?处理反射相关的namespace是什么?

反射(Reflection)是.NET中的重要机制,通过反射,可以在运行时获 得.NET 中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及构造函数等。还可以获得每个成员的名称、限定符和参数等。

System.Reflection命名空间中的类以及System.Type。

序列化

序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。

反射是为了在程序运行时动态获取类的方法和属性,优点:可以实现动态创建对象和编译,有很大的灵活性。缺点:对性能有影响

序列化:将对象状态转换为容易传输的格式的过程。与之相对的是反序列化,它将流转换对象。这两个过程,可以轻松地存储和传输

37. 概述O/R Mapping 的原理

利用反射,配置将对象和数据库表映射。

38. 用Singleton如何写设计模式

static属性里面new ,构造函数private

39. XML

(1) 什么是XML?

XML即可扩展标记语言。eXtensible Markup Language.标记是指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等。如何定义这些标记,即可以选择国际通用的标记语言,比如HTML,也可以使用象

XML这样由相关人士自由决定的标记语言,这就是语言的可扩展性。XML是从SGML中简化修改出来的。它主要用到的有XML、XSL和XPath等。

(2) 列举一下你所了解的XML技术及其应用

xml可以用来做网页(xslt)、可以当作数据库、可以用来保存对象的系列化(web服务好象是基于这个的)。

xml用于配置,用于保存静态数据类型.接触XML最多的是web Services和config

(3) XML与 HTML 的主要区别

  1. XML是区分大小写字母的,HTML不区分。

2.在HTML中,如果上下文清楚地显示出段落或者列表键在何处结尾,那么你可以省略或者之类的结束标记。在XML中,绝对不能省略掉结束标记。

3.在XML中,拥有单个标记而没有匹配的结束标记的元素必须用一个 / 字符作为结尾。这样分析器就知道不用查找结束标记了。

4.在XML中,属性值必须分装在引号中。在HTML中,引号是可用可不用的。

5.在HTML中,可以拥有不带值的属性名。在XML中,所有的属性都必须带有相应的值。

6.XML是用来存储和传输数据的,HTML是用来显示数据的。

40. C#中 property 与 attribute的区别,他们各有什么用处,这种机制的好处在哪里?

一个是属性,用于存取类的字段,一个是特性,用来标识类,方法等的附加性质

41 .当整数a赋值给一个object对象时,整数a将会被?

装箱。

42. publicstatic const int A=1;这段代码有错误么?是什么?

const不能用static修饰。

43. <%# %> 和 <% %> 有什么区别?

<%# %>表示绑定的数据源

<%%>是服务器端代码块

44. C#可否对内存进行直接的操作?

在.net下,.net引用了垃圾回收(GC)功能,它替代了程序员不过在C#中。

C#在unsafe 模式下可以使用指针对内存进行操作, 但在托管模式下不可以使用指针,C#NET默认不运行带指针的,需要设置下,选择项目右键->属性->选择生成->“允许不安全代码”打勾->保存

45. 属性与索引器

(1) C#中索引器是否只能根据数字进行索引?是否允许多个索引器参数?

参数的个数和类型都是任意的。加分的补充回答:用reflector反编译可以看出,索引器的内部本质上就是set_item、get_item方法。

基础知识:

索引的语法:

  • public string this[string s],通过get、set块来定义取值、赋值的逻辑
  • 索引可以有多个参数、参数类型任意
  • 索引可以重载。
  • 如果只有get没有set就是只读的索引。
  • 索引其实就是set_Item、get_Item两个方法。

(2) 属性与索引器的区别

属性 索引器
通过名称标识 通过签名标识
通过简单名称或成员访问来访问 通过元素访问来访问
可以为静态成员或实例成员 必须为实例成员
属性的 get 访问器没有参数 索引器的 get 访问器具有与索引器相同的形参表
属性的 set 访问器包含隐式 value 参数 除了 value 参数外,索引器的 set 访问器还具有与索引器相同的形参表

(3) 属性和public字段的区别是什么?调用set方法为一个属性设值,然后用get方法读取出来的值一定是set进去的值吗?

属性可以对设值、取值的过程进行非法值控制,比如年龄禁止设值负数,而字段则不能进行这样的设置。虽然一般情况下get读取的值就是set设置的值,但是可以让get读取的值不是set设置的值的,极端的例子。Public Age{get{return 100;}set{}}。加分的补充回答:用reflector反编译可以看出,属性内部本质上就是set*、get*方法

  1. class Person
  2. {
  3. public int Age
  4. {
  5. get
  6. {
  7. return 3;
  8. }
  9. set
  10. {
  11. }
  12. }
  13. }
  14. Person p1 = new Person();
  15. p1.Age = 30;
  16. p1.Age++;
  17. Console.Write(p1.Age);//输出3

46. 能用foreach遍历访问的对象的要求

需要实现IEnumerable接口或声明GetEnumerator方法的类型。

47. int、DateTime、string是否可以为null?

null表示“不知道”,而不是“没有”。没有年龄和不知道年龄是不一样。

数据库中null不能用0表示。0岁和不知道多少岁不一样。

Sex is zero。《色即是空》

  1. //int i1 = null;
  2. //int? i2 = null;//值类型后加?就成了可空数据类型
  3. int i3 = i2;//所以把可空的赋值给一定不能为空的会报错。
  4. //int i4 = (int)i2;//可以显式转换,由程序员来保证“一定不为空
  5. //int? i5 = i4;//一定会成功!
  6. //using()→try{]catch{}finally{}
  7. //int?是微软的一个语法糖。是一种和int没有直接关系的Nullable类型
  8. Nullable<int> d1 = new Nullable<int>();//int? d1=null;
  9. Nullable<int> d2 = new Nullable<int>(3);//int? d2=3;
  10. Console.WriteLine(d1==null);

int、DateTime不能,因为其为Struct类型,而结构属于值类型,值类型不能为null,只有引用类型才能被赋值null。string可以为null。

C#中int等值类型不可以为null、而数据库中的int可以为null,这就是纠结的地方。int?就变成了可空的int类型。bool?、DateTime?

  1. int i1 = 3;
  2. int? i2 = i1;
  3. //int i3 = i2;//不能把可能为空的赋值给一定不能为空的变量
  4. int i3 = (int)i2;//显式转换

可空数据类型经典应用场景:三层中的Model属性的设计。

int?翻译生成.Net的Nullable,CTS。

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

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

49. C#中所有对象共同的基类是什么?

System.Object

50. 通过超链接怎样传递中文参数?

用URL编码,通过QueryString传递,用urlencode编码 用urldecode解码

51. string、String;int、Int32;Boolean、bool的区别

String、Int32、Boolean等都属于.Net中定义的类,

而string、int、bool相当于C#中对这些类定义的别名。

52. Server.Transfer和Response.Redirect的区别是什么?(常考)

  1. Server.Transfer仅是服务器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;Response.Redirect则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。
  2. Server.Transfer是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。 这个过程中浏览器和Web服务器之间经过了一次交互。
  3. Response.Redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求。这个过程中浏览器和Web服务器之间经过了两次交互。
  4. Server.Transfer不可以转向外部网站,而Response.Redirect可以。
  5. Server.Execute效果和Server.Transfer类似,但是是把执行的结果嵌入当前页面。

53. 是否可以从一个static方法内部发出对非static方法的调用?

不可以。因为非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用时不需要创建对象,可以直接调用。也就是说,当一个static方法被调用时,可能还没有创建任何实例对象,如果从一个static方法中发出对非static方法的调用,那个非static方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个static方法内部不能发出对非static方法的调用。

54. AJAX解决什么问题?如何使用AJAX?AJAX有什么问题需要注意?项目中哪里用到了AJAX?

AJAX解决的问题就是“无刷新更新页面”,用传统的HTML表单方式进行页面的更新时,每次都要将请求提交到服务器,服务器返回后再重绘界面,这样界面就会经历:提交→变白→重新显示这样一个过程,用户体验非常差,使用AJAX则不会导致页面重新提交、刷新。

AJAX最本质的实现是在Javascript中使用XMLHttpRequest进行Http的请求,开发中通常使用UpdatePanel、JQuery等方式简化AJAX的开发,UpdatePanel的方式实现AJAX最简单,但是数据通讯量比较大,因为要来回传整个ViewState,而且不灵活,对于复杂的需求则可以使用JQuery提供的ajax功能。

加分项:
  1. UpdatePanel的内部原理。
  2. AJAX最重要的问题是无法跨域请求(www.rupeng.com →so.rupeng.com),也就是无法在页面中向和当前域名不同的页面发送请求,可以使用在当前页面所在的域的服务端做代理页面的方式解决。
  3. 在如鹏网项目中发帖的时候显示相关帖的功能、站内搜索项目中显示搜索Suggestion、数据采集项目中都用到了AJAX。
  4. 常考:不用任何框架编写一个AJAX程序。XHR:XmlHttpRequest。背也要背下来!
  5. 如果面试的时候谈AJAX谈到UpdatePanel的时候,就是NB的时候!!!先侃UpdatePanel的原理!引出为什么Dom操作的动态效果在用UpdatePanel提交刷新以后没有了,以及CKEditor被套在UpdatePanel中提交以后也变成了textarea,为什么把Fileupload放到Updatepanel中无法实现无刷新上传。说成是公司内部的一个菜鸟用UpdatePanel遇到这样问题,由于我懂XHR、UpdatePanel的原理,所以轻松解决!UpdatePanel生成的上万行JS脚本,不适合于互联网项目。“WebForm怎么可能把开发人员编程傻子呢!不明白原理苦命呀!还是MVC好呀,MVC。。。。。。。”

55. Application 、Cookie和 Session 两种会话有什么不同?

Application是用来存取整个网站全局的信息。

Session是用来存取与具体某个访问者关联的信息。

Cookie是保存在客户端的,机密信息不能保存在Cookie中,只能放小数据;Session是保存在服务器端的,比较安全,可以放大数据。

谈到Session的时候就侃Session和Cookie的关系:Cookie中的SessionId。和别人对比说自己懂这个原理而给工作带来的方便之处。

56. 说出几个开源软件?

MySQL、Linux、 Discuz、Apache、Paint.Net、Android、Chrome、Notepad++……

开源项目有一些是开发包。开源软件指的是可以直接用的。Jquery、NPOI、ASP.Net MVC、Silverlight Toolkit、AJAX toolkit、json.net

57. 如何把一个array复制到arrayist里

  1. foreach( object arr in array)
  2. arrayist.Add(arr);

58. 用最有效的方法算出2乘以8等于几?

2<<3。位运算是最快,使用的是位运算 逻辑左位移<<。 方法是2<<3相当于0000 0000 0000 0010 (2的16位int二进制)左移三位就是 0000 0000 0001 0000(16的二进制) ### 59. Static Nested Class 和 Inner Class的不同,说得越多越好 StaticNested Class是被声明为静态(static)的内部类,它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化。

60.c#中能使用指针吗?如何使用指针?

能,使用unsafe关键字,开启不安全代码(unsafe code)开发模式直接操作内存,这样就可以使用指针。