-
C#
基础概念二十五问
当初学
C#
时是找个人大概问了一下数据类型和分支语句就
开始做项
目了。这两天又全面的看了一下相关的基础知识
(学而时习之嘛)
,总结了
25
个问题:
1.
静态变量和非静态变量的区别?
和
static readonly
区别?
是什么意思?
ct
是什么意思?
al
修饰符起什么作用?
修饰符是干什么的?
de
和
overload
的区别?
8.
什么是索引指示器?
修饰符是起什么作用?
关键字的含义?
11.
可以使用抽象函数重写基类中
的虚函数吗?
12.
密封类可以有虚函数吗?
13.
如果基类中的虚属性只有一个
属性访问器,
那么继承类重
写
该
属
性
后
可
以
有
几
个
属
性
访
问
器
?
如
果
基
类
中
有
get
和
set
两个呢?
ct
可以和
virtual
一起使用吗?可以和
override
一起
使用吗?
15.
接口可以包含哪些成员?
16.
类和结构的区别?
17.
接口的多继承会带来哪些问题?
18.
抽象类和接口的区别?
19.
别名指示符是什么?
20.
如何释放非托管资源?
21.P/Invoke
是什么?
Builder
和
String
的区别?
it
和
implicit
的含义?
有什么用?
25.
什么是反射?
以下是我做的一份参考答案(
C#
语
言范畴之内)
,如果有不
准确、不全面的,欢迎各位朋友指正!
1.
静态变量和非静态变量的区别?
答:
静态变量:
静态变量使用
static
修饰符进行声明
在所属类被装载时创建
通过类进行访问
所属类的所有实例的同一静态变量都是同一个值
非静态变量:
不带有
static
修饰符声明的变量称做非静态变量
在类被实例化时创建
通过对象进行访问
同一个类的不同实例的同一非静态变量可以是不同的值
示例:
using System;
using c;
using
namespace Example01
{
class Program
{
class Class1
{
public static String
staticStr =
public String notstaticStr =
}
static void Main(string[] args)
{
//
静态变量通过类进行访问,该类所有实例的同一静
态变量都
是同一个值
ine(
cStr);
Class1 tmpObj1
= new Class1();
ticStr =
Class1
tmpObj2 = new Class1();
ticStr =
//
非静态变量通过对象进行访问,
不同对象的同一非
静态变量可以有不同的值
ine(
ticStr);
ine(
ticStr);
ne();
}
}
}
结果:
Class1's staticStr: Class
tmpObj1's notstaticStr: tmpObj1
tmpObj2's notstaticStr:
tmpObj2
和
static
readonly
区别?
答:
const
用
const
< br>修饰符声明的成员叫常量,是在编译期初始化并嵌
入到客户端程序
static
readonly
用
static readonly
修饰符声明的成员依然是变量,
只不过具有
和常量类似的使用
方法:通过类进行访问、初始化后不可以
修改。但与常量不同的是这种变量是在运行期初
始化
示例:
测试类:
using System;
using c;
using
namespace Example02Lib
{
public
class Class1
{
public const String
strConst =
public
static readonly String strStaticReadonly =
donly
//public const String strConst =
//public static readonly String
strStaticReadonly =
eadonly
Changed
}
}
客户端代码:
using System;
using c;
using
using Example02Lib;
namespace Example02
{
class
Program
{
static void Main(string[] args)
{
//
修改
E
xample02
中
Class1
的<
/p>
strConst
初始值后,只
编译
p>
Example02Lib
项目
//
然后
到资源管理器里把新编译的
拷贝
所在的目录,执行
//
切不可在
IDE
里直接调试运行因为这会重新编译整
个解决方案!
p>
!
//
可<
/p>
以
看
到
strC
onst
的
输
出
没
有
改
变
,
而
strStaticReadonly
的输出已经改变
//
表明
Const
变量是在编译期初
始化并嵌入到客户端
程序,而
StaticReadonly<
/p>
是在运行时初始化的
ine(
ine(
StaticReadonly);
ne();
}
}
}
结果:
strConst : Const
strStaticReadonly : StaticReadonly
修改后的示例:
测试类:
using System;
using c;
using
namespace Example02Lib
{
public
class Class1
{
//public const
String strConst =
//public static readonly String strStaticReadonly
=
eadonly
public const String strConst =
public static readonly String
strStaticReadonly =
donly
Changed
}
}
结果
strConst :
Const
strStaticReadonly :
StaticReadonly Changed
是什么意思?
答:
extern
修饰符用于声明由程序集外部实现的成员函数
经常用于系统
API
函数的调用(通过
DllImport
)
。注意,和
DllImport
一起使用时要加上
static
修饰符
也
可
以
用
p>
于
对
于
同
一
程
序
集
不
同
版
本
< br>组
件
的
调
用
(用
extern
声明别名)
不能与
abstract
修饰符同时使用
示例:
using System;
using c;
using
using pServices;
namespace Example03
{
class
Program
{
//
注
意
DllImport
是
一
个
Attribute Property
,
< br>在
pServices
命名空间中定义
< br>
//extern
与
DllImport
一起使用时必须再加上一个
p>
static
修饰符
[DllImport(
public
static extern int MessageBox(int Handle, string
Mes
sage, string Caption, int Type);
static int Main()
{
string
myString;
(
myString =
ne();
return
MessageBox(0, myString,
}
}
}
结果:
ct
是什么意思?
答:
abstract
修饰符可以用于
类、
方法、
属性、事件和索引指示器
(
indexer
)
,表示其为抽象成员
abstract
不可以和
static
、
virtual
、
override
一起使用
声明为
abstract
成员可以
不包括实现代码,但只有类中还有
未实现的抽象成员,该类就不可以被实例化,通常用于
强制
继承类必须实现某一成员
示例:
using System;
using c;
using
namespace Example04
{
#region
基类,抽象类
public abstract class BaseClass
{
//
抽象属性,同时具有
get
和
set
访问器表示继承类
必须
将该属性实现为可读写
public abstract String
Attribute
{
get;
set;
}
//
抽象方法,传入一个字符串参数无返回值
public abstract
void Function(String value);
//
抽
象
事
件
,
类
型
为
< br>系
统
预
定
义
的
代
理
(
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).;
i++)
{
ine(((DeriveClass)sender)[i]);
}
}
static void
Main(string[] args)
{
DeriveClass
tmpObj = new DeriveClass();
ute =
ine(ute);
//
将静态函数
OnFunction
与
tmpObj
对象的
Event
p>
事件
进行关联
+= new
EventHandler(OnFunction);
on(
ne();
}
}
}
结果:
1234567
7
6
5
4
3
2
1
al
修饰符起什么作用?
答:
internal
修饰符可以用于
类型或成员,
使用该修饰符声明的类
型或成员只能在同一程集内
访问
接口的成员不能使用
internal
修饰符
示例
Example05Lib
项目的
Class1
using
System;
using c;
using
namespace
Example05Lib
{
public class Class1
{
internal String strInternal = null;
public String strPublic;
}
}
结果
Example05Lib
项
目
的
Class2
类
可
以
访
问
到
Class1
的
strInternal
成员
Example05
项
目
的
Program
类
无
法
访
问
到
Class1
的
strInternal
成员
修饰符是干什么的?
答:
sealed
修饰符表示密封
用于类时,表示该类不能再被继承,不能和
abstract
同时使
用,因为这两个修饰符在含义上互相排斥
用于方法和属性时,表
示该方法或属性不能再被继承,必须
和
override
关键字一起使用,因为使用
sealed
< br>修饰符的方法
或属性肯定是基类中相应的虚成员
通常用于实现第三方类库时不想被
客户端继承,或用于没有
必要再继承的类以防止滥用继承造成层次结构体系混乱
恰当的利用
sealed
修饰符也
可以提高一定的运行效率,因为
不用考虑继承类会重写该成员
示例:
using System;
using c;
using
namespace Example06
{
class Program
{
class A
{
public virtual void F()
{
ine(
}
public virtual
void G()
{
ine(
}
}
class B : A
{
public sealed override void F()
{
ine(
}
public override
void G()
{
ine(
}
}
class C : B
{
public override void G()
{
ine(
}
}
static void Main(string[] args)
{
new A().F();
new A().G();
new B().F();
new B().G();
new C().F();
new C().G();
ne();
}
}
}
结果:
类
B
在继承类
A
时可以重写两个虚函数,如图所示:
由于类
B
中对
F
方法进行了密封,
类
C
在继承类
B
时只能
重写一个函数,如图所示:
控制台输出结果,类
C
的方法
F
只能是输出
类
B
中对该方
法的实现:
A.F
A.G
B.F
B.G
B.F
C.G
de
和
overload
的区别?
答:
override
表示重写,用于继承类对基类中虚成员的实现
overload
表示重载,用于同一个类中同名方法不同参数(包
括类型不同或个数不同)的
实现
示例:
using System;
using c;
using
namespace Example07
{
class
Program
{
class BaseClass
{
public virtual void F()
{
ine(
}
}
class DeriveClass : BaseClass
{
public override void F()
{
base.F();
ine(
}
public void Add(int Left, int Right)
{
ine(
}
public void
Add(double Left, double Right)
{
ine(
}
}
static void Main(string[] args)
{
DeriveClass tmpObj = new
DeriveClass();
tmpObj.F();
(1,
2);
(1.1, 2.2);
ne();
}
}
}
结果:
BaseClass.F
DeriveClass.F
Add for Int: 3
Add for int: 3.3
8.
什么是索引指示器?
答:
实现索引指示器(
indexer
)的类可以象数组那样使用其实例
后的
对象,但与数组不同的是索引指示器的参数类型不仅限
于
int
简单来说,其本质就是一个含参数属性
示例:
using System;
using c;
using
namespace Example08
{
public
class Point
{
private double x,
y;
public
Point(double X, double Y)
{
x = X;
y = Y;
}
//
重写
ToStr
ing
方法方便输出
public override string
ToString()
{
return
(
}
}
public
class Points
{
Point[] points;
public
Points(Point[] Points)
{
points =
Points;
}
public int
PointNumber
{
get
{
return
}
}
//
实现索引访问器
public Point this[int Index]
{
get
{
return
points[Index];
}
}
}
//
感谢
watson
hua(/)
的指点
//
索引指示器的实质是含参属性,参数并不只限于
int
class WeatherOfWeek
{
public string this[int Index]
{
get
{
//
注意
case
段使用
retu
rn
直接返回所以不需要
break
switch (Index)
{
case 0:
{
return
}
case
5:
{
return
}
default:
{
return
}
}
}
}
public string this[string Day]
{
get
{
string
TodayWeather = null;
//switch
的标准写法
switch (Day)
{
case
{
TodayWeather =
break;
}
case
{
TodayWeather =
break;
}
default:
{
TodayWeather =
break;
}
}
return
TodayWeather;
}
}
}
class
Program
{
static void Main(string[] args)
{
Point[] tmpPoints = new
Point[10];
for
(int i = 0; i < i++)
{
tmpPoints[i] = new Point(i, (i));
}
Points tmpObj =
new Points(tmpPoints);
for (int i = 0; i < umber; i++)
{
ine(tmpObj[i]);
}
string[] Week =
new string[] {
esday
WeatherOfWeek
tmpWeatherOfWeek = new WeatherOf
Week();
for (int i = 0;
i < 6; i++)
{
ine(tmpWeatherOfWeek[i]);
}
foreach
(string tmpDay in Week)
{
ine(tmpWeatherOfWeek[tmpDay]);
}
ne();
}
}
}
结果:
X: 0 , Y: 0
X: 1
, Y: 0.84147
X: 2 , Y:
0.982
X: 3 , Y: 0.14112
X: 4 , Y: -0.7568
X: 5 , Y:
-0.958924274663138
X: 6 ,
Y: -0.2794
X: 7 , Y:
0.656986598718789
X: 8 , Y:
0.989358246623382
X: 9 , Y:
0.4757
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!
修饰符是起什么作用?
答:
new
修饰符与
new
操作符是两个概念
new
修饰符用于声明类或类的成
员,表示隐藏了基类中同名
的成员。而
new
操作符用于实例化一个类型
new
修饰符只能用于继承类,一般用于弥补基类设计的不足
new
修饰符和
override
修饰符
不可同时用在一个成员上,因
为这两个修饰符在含义上互相排斥
示例:
using System;
using c;
using
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)
{
ine();
ine();
ne();
}
}
}
结果:
3.1415
3.1415926
关键字的含义?
答:
this
是一个保留字,仅限于构造函数和方法成员中使用
在类的构造函数中出现表示对正在
构造的对象本身的引用,
在类的方法中出现表示对调用该方法的对象的引用,在结构
p>
的构造上函数中出现表示对正在构造的结构的引用,在结构
的方法中
出现表示对调用该方法的结果的引用
this
保留字不能用于静态成员
的实现里,因为这时对象或结
构并未实例化
在
C#
系
统
中
,
p>
this
实
际
上
是
一
个
常
p>
量
,
所
以
不
能
使
用
this++
这样的运算
this
保留字一般用于限定同名的隐藏成员、将对象本身做为
参数、声明索引访问器、判断传
入参数的对象是否为本身
示例:
using System;
using c;
using
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
(
UnitTransClass.C2F(this));
}
//
由于好奇,在
这做了一个效率测试,想看看到底哪种
方式访问成员变量更快,结论:区别不大。
。
。
public string Test1()
{
long vTickCount = unt;
for (int i = 0;
i < 10000000; i++)
= ng();
return
(
unt - vTickCount);
}
public string Test2()
{
long
vTickCount = unt;
for (int i = 0; i < 10000000; i++)
value = ng();
return
(
unt - 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);
ine(tmpObj);
ine(1());
ine(2());
ne();
}
}
}
结果:
37.5 Celsius = 99.5 Fahrenheit
Have this.: 4375 MSEL
Don't have this.: 4406 MSEL
11.
可以使用抽象函数重写基类中的虚函数吗?
答:
可以,但需使用
new
修饰符显式
声明,表示隐藏了基类中该
函数的实现
示例
:
class
BaseClass
{
public virtual void F()
{
ine(
}
}
abstract class DeriveClass :
BaseClass
{
public new abstract void F();
}
12.
密封类可以有虚函数吗?
答:
可以,基类中的虚函数将隐式的转
化为非虚函数,但密封类
本身不能再增加新的虚函数
示例:
class
BaseClass
{
public virtual void F()
{
ine(
}
}
sealed class DeriveClass :
BaseClass
{
//
基类中的虚函数
F
被隐式的转化为非虚函数
//
密封类中不能再声明新的虚函数
G
//public virtual
void G()
//{
//
ine(
//}
}
13.
如果基类中的虚属性只有一个属性访问器,
那么继承
类重
写
该
属
性
后
可
以
有
p>
几
个
属
性
访
问
器
?
如
果
基
类
< br>中
有
get
和
set
两个呢?
答:
<
/p>
如果基类中的虚属性只有一个属性访问器,那么继承类重写
该属性
后也应只有一个。
如果基类中有
get
和
set
两个属性访
问器,那么继承类中可以只有一个也可以同时有两个属性访
问器
ct
可以和
virtual
一起使用吗?可以和
override
一起
使用吗?
答:
abstract
修饰符不可以和
static
、
virtual
和
override
修饰符一起
使用
15.
接口可以包含哪些成员?
答:
接口可以包含属性、方法、索引指
示器和事件,但不能包含
常量、域、操作符、构造函数和析构函数,而且也不能包含
p>
任何静态成员