这段时间一边忙工做,一边在找新工做,面试过程当中不少基础性的客观题,我在实际工做中真的用的不多,学过或者看过的也忘的差很少了,不免对最简单的问题产生一些迷惑,但愿这篇帖子能给你们带来一些帮助。这多是最最简单,我以为对我来讲起码面试前可能须要温习一下,我比较紧张啦。。。。。。很差笑话我。
转自:
http://bbs.51aspx.com/showtopic-2879.html
1.静态变量和非静态变量的区别?
2.const 和 static readonly 区别?
3.extern 是什么意思?
4.abstract 是什么意思?
5.internal 修饰符起什么做用?
6.sealed 修饰符是干什么的?
7.override 和 overload 的区别?
8.什么是索引指示器?
9.new 修饰符是起什么做用?
10.this 关键字的含义?
11.可使用抽象函数重写基类中的虚函数吗?
12.密封类能够有虚函数吗?
13.若是基类中的虚属性只有一个属性访问器,那么继承类重写该属性后能够有几个属性访问器?若是基类中有 get 和 set 两个呢?
14.abstract 能够和 virtual 一块儿使用吗?能够和 override 一块儿使用吗?
15.接口能够包含哪些成员?
16.类和结构的区别?
17.接口的多继承会带来哪些问题?
18.抽象类和接口的区别?
19.别名指示符是什么?
20.如何释放非托管资源?
21.P/Invoke是什么?
22.StringBuilder 和 String 的区别?
23.explicit 和 implicit 的含义?
24.params 有什么用?
25.什么是反射?
参考答案(C# 语言范畴以内)
1.静态变量和非静态变量的区别?
答:
静态变量:
静态变量使用 static 修饰符进行声明
在所属类被装载时建立
经过类进行访问
所属类的全部实例的同一静态变量都是同一个值
非静态变量:
不带有 static 修饰符声明的变量称作非静态变量
在类被实例化时建立
经过对象进行访问
同一个类的不一样实例的同一非静态变量能够是不一样的值
示例:

Code
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Example01
{
class
Program
{
class
Class1
{
public
static
String staticStr
=
&
amp;quot;Class
&
amp;quot;;
public
String notstaticStr
=
&
amp;quot;Obj
&
amp;quot;;
}
static
void
Main(
string
[] args)
{
//
静态变量经过类进行访问,该类全部实例的同一静态变量都是同一个值
Console.WriteLine(
&
amp;quot;Class1
'
s staticStr: {0}", Class1.staticStr);
Class1 tmpObj1
=
new
Class1();
tmpObj1.notstaticStr
=
&
amp;quot;tmpObj1
&
amp;quot;;
Class1 tmpObj2
=
new
Class1();
tmpObj2.notstaticStr
=
&
amp;quot;tmpObj2
&
amp;quot;;
//
非静态变量经过对象进行访问,不一样对象的同一非静态变量能够有不一样的值
Console.WriteLine(
&
amp;quot;tmpObj1
'
s notstaticStr: {0}", tmpObj1.notstaticStr);
Console.WriteLine(
&
amp;quot;tmpObj2
'
s notstaticStr: {0}", tmpObj2.notstaticStr);
Console.ReadLine();
}
}
}
结果:
Class1
'
s staticStr: Class
tmpObj1
'
s notstaticStr: tmpObj1
tmpObj2
'
s notstaticStr: tmpObj2
2.const 和 static readonly 区别?
答:
const
用 const 修饰符声明的成员叫常量,是在编译期初始化并嵌入到客户端程序
static readonly
用 static readonly 修饰符声明的成员依然是变量,只不过具备和常量相似的使用方法:经过类进行访问、初始化后不能够修改。但与常量不一样的是这种变量是在运行期初始化
示例:

Code
测试类:
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Example02Lib
{
public
class
Class1
{
public
const
String strConst
=
&
amp;quot;Const
&
amp;quot;;
public
static
readonly
String strStaticReadonly
=
&
amp;quot;StaticReadonly
&
amp;quot;;
//
public const String strConst = "Const Changed";
//
public static readonly String strStaticReadonly = "StaticReadonly Changed";
}
//
5-1-a-s-p-x
}
客户端代码:
using
System;
using
System.Collections.Generic;
using
System.Text;
using
Example02Lib;
namespace
Example02
{
class
Program
{
static
void
Main(
string
[] args)
{
//
修改Example02中Class1的strConst初始值后,只编译Example02Lib项目
//
而后到资源管理器里把新编译的Example02Lib.dll拷贝Example02.exe所在的目录,执行Example02.exe
//
切不可在IDE里直接调试运行由于这会从新编译整个解决方案!!
//
能够看到strConst的输出没有改变,而strStaticReadonly的输出已经改变
//
代表Const变量是在编译期初始化并嵌入到客户端程序,而StaticReadonly是在运行时初始化的
Console.WriteLine(
&
amp;quot;strConst : {
0
}
&
amp;quot;, Class1.strConst);
Console.WriteLine(
&
amp;quot;strStaticReadonly : {
0
}
&
amp;quot;, Class1.strStaticReadonly);
Console.ReadLine();
}
}
}
结果:
strConst : Const
strStaticReadonly : StaticReadonly
修改后的示例:
测试类:
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Example02Lib
{
public
class
Class1
{
//
public const String strConst = "Const";
//
public static readonly String strStaticReadonly = "StaticReadonly";
public
const
String strConst
=
&
amp;quot;Const Changed
&
amp;quot;;
public
static
readonly
String strStaticReadonly
=
&
amp;quot;StaticReadonly Changed
&
amp;quot;;
}
}
结果
strConst : Const
strStaticReadonly : StaticReadonly Changed
3.extern 是什么意思?
答:
extern 修饰符用于声明由程序集外部实现的成员函数
常常用于系统API函数的调用(经过 DllImport )。注意,和DllImport一块儿使用时要加上 static 修饰符
也能够用于对于同一程序集不一样版本组件的调用(用 extern 声明别名)
不能与 abstract 修饰符同时使用;
示例:

Code
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Runtime.InteropServices;
namespace
Example03
{
class
Program
{
//
注意DllImport是一个Attribute Property,在System.Runtime.InteropServices命名空间中定义
//
extern与DllImport一块儿使用时必须再加上一个static修饰符
[DllImport(
&
amp;quot;User32.dll
&
amp;quot;)]
public
static
extern
int
MessageBox(
int
Handle,
string
Message,
string
Caption,
int
Type);
static
int
Main()
{
string
myString;
Console.Write(
&
amp;quot;Enter your message:
&
amp;quot;);
myString
=
Console.ReadLine();
return
MessageBox(
0
, myString,
&
amp;quot;My Message Box
&
amp;quot;,
0
);
}
}
}
结果:
4.abstract 是什么意思?
答:
abstract 修饰符能够用于类、方法、属性、事件和索引指示器(indexer),表示其为抽象成员
abstract 不能够和 static 、virtual 、override 一块儿使用
声明为 abstract 成员能够不包括实现代码,但只有类中还有未实现的抽象成员,该类就不能够被实例化,一般用于强制继承类必须实现某一成员
示例:

Code
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Example04
{
#region
基类,抽象类
public
abstract
class
BaseClass
{
//
抽象属性,同时具备get和set访问器表示继承类必须将该属性实现为可读写
public
abstract
String Attribute
{
get
;
set
;
}
//
抽象方法,传入一个字符串参数无返回值
public
abstract
void
Function(String value);
//
抽象事件,类型为系统预约义的代理(delegate):EventHandler
public
abstract
event
EventHandler Event;
//
抽象索引指示器,只具备get访问器表示继承类必须将该索引指示器实现为只读
public
abstract
Char
this
[
int
Index]
{
get
;
}
}
#endregion
#region
继承类
public
class
DeriveClass : BaseClass
{
private
String attribute;
public
override
String Attribute
{
get
{
return
attribute;
}
set
{
attribute
=
value;
}
}
public
override
void
Function(String value)
{
attribute
=
value;
if
(Event
!=
null
)
{
Event(
this
,
new
EventArgs());
}
}
public
override
event
EventHandler Event;
public
override
Char
this
[
int
Index]
{
get
{
return
attribute[Index];
}
}
}
#endregion
class
Program
{
static
void
OnFunction(
object
sender, EventArgs e)
{
for
(
int
i
=
0
; i
<
((DeriveClass)sender).Attribute.Length; i
++
)
{
Console.WriteLine(((DeriveClass)sender));
}
}
static
void Main(string
[] args)
{
DeriveClass tmpObj =
new
DeriveClass();
tmpObj.Attribute =
&quot;1234567&
amp;quot;;
Console.WriteLine(tmpObj.Attribute);
//将静态函数OnFunction与tmpObj对象的Event事件进行关联
tmpObj.Event +=
new
EventHandler(OnFunction);
tmpObj.Function(&quot;7654321&
amp;quot;);
Console.ReadLine();
}
}
}
结果:
1234567
7
6
5
4
3
2
1
5.internal 修饰符起什么做用?
答:
internal 关键字是类型和类型成员的访问修饰符。只有在同一程序集的文件中,内部类型或成员才是可访问的
接口的成员不能使用 internal 修饰符;
应用场合:
内部访问一般用于基于组件的开发,由于它使一组组件可以以私有方式进行合做,而没必要向应用程序代码的其他部分公开。例如,用于生成图形用户界面的框架能够提供“控件”类和“窗体”类,这些类经过使用具备内部访问能力的成员进行合做。因为这些成员是内部的,它们不向正在使用框架的代码公开。
示例

Code
程序集A (AssemblyA)
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
AssemblyA
{
public
class
ClassA
{
internal
string internalName =
" internal name"
;
public
string pubName =
" public name"
;
public
string
GetName()
{
return internalName +","+
pubName;
}
}
public
class
ClassB
{
public
string
GetName()
{
ClassA ca =
new
ClassA();
return ca.internalName +
ca.pubName;
}
}
}
程序集B (AssemblyB)
using
System;
using
System.Collections.Generic;
using
System.Text;
using
AssemblyA;
namespace
AssemblyB
{
public
class
ClassC
{
public
string
GetName()
{
ClassA ca =
new
ClassA();
string pubName = ca.pubName; //正确
string internalName = ca.internalName; //错误!!!!!! 不可访问;
return
pubName;
}
}
}
6.sealed 修饰符是干什么的?
答:
sealed 修饰符表示密封
用于类时,表示该类不能再被继承,不能和 abstract 同时使用,由于这两个修饰符在含义上互相排斥
用于方法和属性时,表示该方法或属性不能再被继承,必须和 override 关键字一块儿使用,由于使用 sealed 修饰符的方法或属性确定是基类中相应的虚成员
一般用于实现第三方类库时不想被客户端继承,或用于没有必要再继承的类以防止滥用继承形成层次结构体系混乱
恰当的利用 sealed 修饰符也能够提升必定的运行效率,由于不用考虑继承类会重写该成员
示例:

Code
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Example06
{
class
Program
{
class
A
{
public
virtual
void
F()
{
Console.WriteLine(&quot;A.F&
amp;quot;);
}
public
virtual
void
G()
{
Console.WriteLine(&quot;A.G&
amp;quot;);
}
}
class
B : A
{
public
sealed
override
void
F()
{
Console.WriteLine(&quot;B.F&
amp;quot;);
}
public
override
void
G()
{
Console.WriteLine(&quot;B.G&
amp;quot;);
}
}
class
C : B
{
public
override
void
G()
{
Console.WriteLine(&quot;C.G&
amp;quot;);
}
}
static
void Main(string
[] args)
{
new
A().F();
new
A().G();
new
B().F();
new
B().G();
new
C().F();
new
C().G();
Console.ReadLine();
}
}
}
结果:
类 B 在继承类 A 时能够重写两个虚函数,如图所示:
因为类 B 中对 F 方法进行了密封, 类 C 在继承类 B 时只能重写一个函数,如图所示:
控制台输出结果,类 C 的方法 F 只能是输出 类B 中对该方法的实现:
A.F
A.G
B.F
B.G
B.F
C.G
7.override 和 overload 的区别?
答:
override 表示重写,用于继承类对基类中虚成员的实现
overload 表示重载,用于同一个类中同名方法不一样参数(包括类型不一样或个数不一样)的实现
示例:

Code
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Example07
{
class
Program
{
class
BaseClass
{
public
virtual
void
F()
{
Console.WriteLine(&quot;BaseClass.F&
amp;quot;);
}
}
class
DeriveClass : BaseClass
{
public
override
void
F()
{
base
.F();
Console.WriteLine(&quot;DeriveClass.F&
amp;quot;);
}
public
void Add(int Left, int
Right)
{
Console.WriteLine(&quot;Add for Int: {0}&quot;, Left +
Right);
}
public
void Add(double Left, double
Right)
{
Console.WriteLine(&quot;Add for
int: {0}&quot;, Left +
Right);
}
}
static
void Main(string
[] args)
{
DeriveClass tmpObj =
new
DeriveClass();
tmpObj.F();
tmpObj.Add(1, 2
);
tmpObj.Add(1.1, 2.2
);
Console.ReadLine();
}
}
}
结果:
BaseClass.F
DeriveClass.F
Add for Int: 3
Add
for
int: 3.3
8.什么是索引指示器?
答:
实现索引指示器(indexer)的类能够象数组那样使用其实例后的对象,但与数组不一样的是索引指示器的参数类型不只限于int
简单来讲,其本质就是一个含参数属性
示例:

Code
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Example08
{
public
class
Point
{
private
double
x, y;
public Point(double X, double
Y)
{
x =
X;
y =
Y;
}
//重写ToString方法方便输出
public
override
string
ToString()
{
return String.Format(&quot;X: {0} , Y: {1}&
amp;quot;, x, y);
}
}
public
class
Points
{
Point[] points;
public
Points(Point[] Points)
{
points =
Points;
}
public
int
PointNumber
{
get
{
return
points.Length;
}
}
//实现索引访问器
public Point this[int
Index]
{
get
{
return
points[Index];
}
}
}
//感谢watson hua(http://huazhihao.cnblogs.com/
)的指点
//索引指示器的实质是含参属性,参数并不仅限于int
class
WeatherOfWeek
{
public
string
this[int
Index]
{
get
{
//注意case段使用return直接返回因此不须要break
switch
(Index)
{
case
0
:
{
return
&quot;Today is cloudy!&
amp;quot;;
}
case
5
:
{
return
&quot;Today is thundershower!&
amp;quot;;
}
default
:
{
return
&quot;Today is fine!&
amp;quot;;
}
}
}
}
public
string
this[string
Day]
{
get
{
string TodayWeather =
null
;
//switch的标准写法
switch
(Day)
{
case
&quot;Sunday&
amp;quot;:
{
TodayWeather =
&quot;Today is cloudy!&
amp;quot;;
break
;
}
case
&quot;Friday&
amp;quot;:
{
TodayWeather =
&quot;Today is thundershower!&
amp;quot;;
break
;
}
default
:
{
TodayWeather =
&quot;Today is fine!&
amp;quot;;
break
;
}
}
return
TodayWeather;
}
}
}
class
Program
{
static
void Main(string
[] args)
{
Point[] tmpPoints =
new Point[10
];
for (int i =
0; i < tmpPoints.Length; i++
)
{
tmpPoints =
new
Point(i, Math.Sin(i));
}
Points tmpObj =
new
Points(tmpPoints);
for (int i =
0; i < tmpObj.PointNumber; i++
)
{
Console.WriteLine(tmpObj);
}
string[] Week =
new
string[] { &quot;Sunday&quot;, &quot;Monday&quot;, &quot;Tuesday&quot;, &quot;Wednesday&quot;, &quot;Thursday&quot;, &quot;Friday&quot;, &quot;Staurday&
amp;quot;};
WeatherOfWeek tmpWeatherOfWeek =
new
WeatherOfWeek();
for (int i =
0; i <
6; i++
)
{
Console.WriteLine(tmpWeatherOfWeek);
}
foreach (string tmpDay in
Week)
{
Console.WriteLine(tmpWeatherOfWeek[tmpDay]);
}
Console.ReadLine();
}
}
}
结果:
X: 0 , Y: 0
X:
1 , Y: 0.841470984807897
X:
2 , Y: 0.909297426825682
X:
3 , Y: 0.141120008059867
X:
4 , Y: -0.756802495307928
X:
5 , Y: -0.958924274663138
X:
6 , Y: -0.279415498198926
X:
7 , Y: 0.656986598718789
X:
8 , Y: 0.989358246623382
X:
9 , Y: 0.412118485241757
Today
is cloudy!
Today
is fine!
Today
is fine!
Today
is fine!
Today
is fine!
Today
is thundershower!
Today
is cloudy!
Today
is fine!
Today
is fine!
Today
is fine!
Today
is fine!
Today
is thundershower!
Today
is fine!
9.new 修饰符是起什么做用?
答:
new 修饰符与 new 操做符是两个概念
new 修饰符用于声明类或类的成员,表示隐藏了基类中同名的成员。而new 操做符用于实例化一个类型
new 修饰符只能用于继承类,通常用于弥补基类设计的不足
new 修饰符和 override 修饰符不可同时用在一个成员上,由于这两个修饰符在含义上互相排斥
示例:

Code
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Example09
{
class
BaseClass
{
//基类设计者声明了一个PI的公共变量,方便进行运算
public
static
double PI =
3.1415
;
}
class
DervieClass : BaseClass
{
//继承类发现该变量的值不能知足运算精度,因而能够经过new修饰符显示隐藏基类中的声明
public
new
static
double PI =
3.1415926
;
}
class
Program
{
static
void Main(string
[] args)
{
Console.WriteLine(BaseClass.PI);
Console.WriteLine(DervieClass.PI);
Console.ReadLine();
}
}
}
结果:
3.1415
3.1415926
10.this 关键字的含义?
答:
this 是一个保留字,仅限于构造函数和方法成员中使用
在类的构造函数中出现表示对正在构造的对象自己的引用,在类的方法中出现表示对调用该方法的对象的引用,在结构的构造上函数中出现表示对正在构造的结构的引用,在结构的方法中出现表示对调用该方法的结果的引用
this 保留字不能用于静态成员的实现里,由于这时对象或结构并未实例化
在 C# 系统中,this 其实是一个常量,因此不能使用 this++ 这样的运算
this 保留字通常用于限定同名的隐藏成员、将对象自己作为参数、声明索引访问器、判断传入参数的对象是否为自己
示例:

Code
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Example10
{
class
Class1
{
private
double
c;
private
string
value;
public
double
C
{
get
{
return
c;
}
}
public Class1(double
c)
{
//限定同名的隐藏成员
this.c =
c;
}
public
Class1(Class1 value)
{
//用对象自己实例化本身没有意义
if (this
!=
value)
{
c =
value.C;
}
}
public
override
string
ToString()
{
//将对象自己作为参数
return
string.Format(&quot;{0} Celsius = {1} Fahrenheit&quot;, c, UnitTransClass.C2F(this
));
}
//因为好奇,在这作了一个效率测试,想看看到底哪一种方式访问成员变量更快,结论:区别不大。。。
public
string
Test1()
{
long vTickCount =
Environment.TickCount;
for (int i =
0; i <
10000000; i++
)
this.value =
i.ToString();
return
string.Format(&quot;Have this.: {0} MSEL&quot;, Environment.TickCount -
vTickCount);
}
public
string
Test2()
{
long vTickCount =
Environment.TickCount;
for (int i =
0; i <
10000000; i++
)
value =
i.ToString();
return
string.Format(&quot;Don't have this.: {0} MSEL", Environment.TickCount - vTickCount);
}
}
class
UnitTransClass
{
public
static
double
C2F(Class1 value)
{
//摄氏到华氏的转换公式
return
1.8
* value.C +
32
;
}
}
class
Program
{
static
void Main(string
[] args)
{
Class1 tmpObj =
new Class1(37.5
);
Console.WriteLine(tmpObj);
Console.WriteLine(tmpObj.Test1());
Console.WriteLine(tmpObj.Test2());
Console.ReadLine();
}
}
}
结果:
37.5 Celsius =
99.5
Fahrenheit
Have this.: 4375
MSEL
Don't have this.: 4406 MSEL