您的位置:首页 > 编程语言 > C#

C#基础概念二十五问

2007-07-13 16:32 435 查看
C#基础概念二十五问
注:本文部份资料来自网络,如有侵权,请与我联系,我会在第一时间声明引用或将其删除!

当初学C#时是找个人大概问了一下数据类型和分支语句就开始做项目了。这两天又全面的看了一下相关的基础知识(学而时习之嘛),总结了25个问题:

1.静态成员和非静态成员的区别?
2.const和staticreadonly区别?
3.extern是什么意思?
4.abstract是什么意思?
5.internal修饰符起什么作用?
6.sealed修饰符是干什么的?
7.override和overload的区别?
8.什么是索引指示器?
9.new修饰符是起什么作用?
10.this关键字的含义?
11.可以使用抽象函数重写基类中的虚函数吗?
12.密封类可以有虚函数吗?
13.什么是属性访问器?
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修饰符声明的变量称做非静态变量,在对象被实例化时创建,通过对象进行访问

一个类的所有实例的同一静态变量都是同一个值,同一个类的不同实例的同一非静态变量可以是不同的值

静态函数的实现里不能使用非静态成员,如非静态变量、非静态函数等

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample01

{

classProgram

{

classClass1

{

publicstaticStringstaticStr="Class";

publicStringnotstaticStr="Obj";

}

staticvoidMain(string[]args)

{

//静态变量通过类进行访问,该类所有实例的同一静态变量都是同一个值

Console.WriteLine("Class1'sstaticStr:{0}",Class1.staticStr);


Class1tmpObj1=newClass1();

tmpObj1.notstaticStr="tmpObj1";

Class1tmpObj2=newClass1();

tmpObj2.notstaticStr="tmpObj2";


//非静态变量通过对象进行访问,不同对象的同一非静态变量可以有不同的值

Console.WriteLine("tmpObj1'snotstaticStr:{0}",tmpObj1.notstaticStr);

Console.WriteLine("tmpObj2'snotstaticStr:{0}",tmpObj2.notstaticStr);


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
Class1'sstaticStr:Class
tmpObj1'snotstaticStr:tmpObj1
tmpObj2'snotstaticStr:tmpObj2

2.const和staticreadonly区别?

答:

const

用const修饰符声明的成员叫常量,是在编译期初始化并嵌入到客户端程序

staticreadonly

用staticreadonly修饰符声明的成员依然是变量,只不过具有和常量类似的使用方法:通过类进行访问、初始化后不可以修改。但与常量不同的是这种变量是在运行期初始化

示例:

测试类:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample02Lib

{

publicclassClass1

{

publicconstStringstrConst="Const";

publicstaticreadonlyStringstrStaticReadonly="StaticReadonly";

//publicconstStringstrConst="ConstChanged";

//publicstaticreadonlyStringstrStaticReadonly="StaticReadonlyChanged";

}

}


客户端代码:


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}


usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;

usingExample02Lib;


namespaceExample02

{

classProgram

{

staticvoidMain(string[]args)

{

//修改Example02中Class1的strConst初始值后,只编译Example02Lib项目

//然后到资源管理器里把新编译的Example02Lib.dll拷贝Example02.exe所在的目录,执行Example02.exe

//切不可在IDE里直接调试运行因为这会重新编译整个解决方案!!


//可以看到strConst的输出没有改变,而strStaticReadonly的输出已经改变

//表明Const变量是在编译期初始化并嵌入到客户端程序,而StaticReadonly是在运行时初始化的

Console.WriteLine("strConst:{0}",Class1.strConst);

Console.WriteLine("strStaticReadonly:{0}",Class1.strStaticReadonly);


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
strConst:Const
strStaticReadonly:StaticReadonly

修改后的示例:

测试类:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample02Lib

{

publicclassClass1

{

//publicconstStringstrConst="Const";

//publicstaticreadonlyStringstrStaticReadonly="StaticReadonly";

publicconstStringstrConst="ConstChanged";

publicstaticreadonlyStringstrStaticReadonly="StaticReadonlyChanged";

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果

strConst:Const
strStaticReadonly:StaticReadonlyChanged

3.extern是什么意思?

答:

extern修饰符用于声明由程序集外部实现的成员函数

经常用于系统API函数的调用(通过DllImport)。注意,和DllImport一起使用时要加上static修饰符

也可以用于对于同一程序集不同版本组件的调用(用extern声明别名)

不能与abstract修饰符同时使用

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;

usingSystem.Runtime.InteropServices;


namespaceExample03

{

classProgram

{

//注意DllImport是一个AttributeProperty,在System.Runtime.InteropServices命名空间中定义

//extern与DllImport一起使用时必须再加上一个static修饰符

[DllImport("User32.dll")]

publicstaticexternintMessageBox(intHandle,stringMessage,stringCaption,intType);


staticintMain()

{

stringmyString;

Console.Write("Enteryourmessage:");

myString=Console.ReadLine();

returnMessageBox(0,myString,"MyMessageBox",0);

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:




4.abstract是什么意思?

答:

abstract修饰符可以用于类、方法、属性、事件和索引指示器(indexer),表示其为抽象成员

abstract不可以和static、virtual一起使用

声明为abstract成员可以不包括实现代码,但只要类中还有未实现的抽象成员(即抽象类),那么它的对象就不能被实例化,通常用于强制继承类必须实现某一成员

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample04

{

#region基类,抽象类

publicabstractclassBaseClass

{

//抽象属性,同时具有get和set访问器表示继承类必须将该属性实现为可读写

publicabstractStringAttribute

{

get;

set;

}


//抽象方法,传入一个字符串参数无返回值

publicabstractvoidFunction(Stringvalue);


//抽象事件,类型为系统预定义的代理(delegate):EventHandler

publicabstracteventEventHandlerEvent;


//抽象索引指示器,只具有get访问器表示继承类必须将该索引指示器实现为只读

publicabstractCharthis[intIndex]

{

get;

}

}

#endregion


#region继承类

publicclassDeriveClass:BaseClass

{

privateStringattribute;


publicoverrideStringAttribute

{

get

{

returnattribute;

}

set

{

attribute=value;

}

}

publicoverridevoidFunction(Stringvalue)

{

attribute=value;

if(Event!=null)

{

Event(this,newEventArgs());

}

}

publicoverrideeventEventHandlerEvent;

publicoverrideCharthis[intIndex]

{

get

{

returnattribute[Index];

}

}

}

#endregion


classProgram

{

staticvoidOnFunction(objectsender,EventArgse)

{

for(inti=0;i<((DeriveClass)sender).Attribute.Length;i++)

{

Console.WriteLine(((DeriveClass)sender)[i]);

}

}

staticvoidMain(string[]args)

{

DeriveClasstmpObj=newDeriveClass();


tmpObj.Attribute="1234567";

Console.WriteLine(tmpObj.Attribute);


//将静态函数OnFunction与tmpObj对象的Event事件进行关联

tmpObj.Event+=newEventHandler(OnFunction);


tmpObj.Function("7654321");


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
1234567
7
6
5
4
3
2
1

5.internal修饰符起什么作用?

答:

internal修饰符可以用于类型或成员,使用该修饰符声明的类型或成员只能在同一程集内访问

接口的成员不能使用internal修饰符

值得注意的是,如果为internal成员加上了protected修饰符,这时的访问级别为internal或protected。只是看字面意思容易弄错,许多人认为internalprotected应该是“只有同一个程序集中的子类可以访问”,但其实它表示“同一个程序集中的所有类,以及所有程序集中的子类都可以访问”

示例

Example05Lib项目的Class1

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample05Lib

{

publicclassClass1

{

internalStringstrInternal=null;

publicStringstrPublic;

internalprotectedStringstrInternalProtected=null;

}

}


.csharpcode,.csharpcodepre{   font-size:small;   color:black;   font-family:consolas,"CourierNew",courier,monospace;   background-color:#ffffff;   /*white-space:pre;*/}.csharpcodepre{margin:0em;}.csharpcode.rem{color:#008000;}.csharpcode.kwrd{color:#0000ff;}.csharpcode.str{color:#006080;}.csharpcode.op{color:#0000c0;}.csharpcode.preproc{color:#cc6633;}.csharpcode.asp{background-color:#ffff00;}.csharpcode.html{color:#800000;}.csharpcode.attr{color:#ff0000;}.csharpcode.alt{   background-color:#f4f4f4;   width:100%;   margin:0em;}.csharpcode.lnum{color:#606060;}
结果
Example05Lib项目的Class2类可以访问到Class1的strInternal成员,当然也可以访问到strInternalProtected成员,因为他们在同一个程序集里



Example05项目里的Class3类无法访问到Class1的strInternal成员,因为它们不在同一个程序集里。但却可以访问到strInternalProtected成员,因为Class3是Class1的继承类



Example05项目的Program类既无法访问到Class1的strInternal成员,也无法访问到strInternalProtected成员,因为它们既不在同一个程序集里也不存在继承关系





6.sealed修饰符是干什么的?

答:

sealed修饰符表示密封

用于类时,表示该类不能再被继承,不能和abstract同时使用,因为这两个修饰符在含义上互相排斥

用于方法和属性时,表示该方法或属性不能再被继承,必须和override关键字一起使用,因为使用sealed修饰符的方法或属性肯定是基类中相应的虚成员

通常用于实现第三方类库时不想被客户端继承,或用于没有必要再继承的类以防止滥用继承造成层次结构体系混乱

恰当的利用sealed修饰符也可以提高一定的运行效率,因为不用考虑继承类会重写该成员

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample06

{

classProgram

{

classA

{

publicvirtualvoidF()

{

Console.WriteLine("A.F");

}

publicvirtualvoidG()

{

Console.WriteLine("A.G");

}

}

classB:A

{

publicsealedoverridevoidF()

{

Console.WriteLine("B.F");

}

publicoverridevoidG()

{

Console.WriteLine("B.G");

}

}

classC:B

{

publicoverridevoidG()

{

Console.WriteLine("C.G");

}

}

staticvoidMain(string[]args)

{

newA().F();

newA().G();

newB().F();

newB().G();

newC().F();

newC().G();


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
类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表示重载,用于同一个类中同名方法不同参数(包括类型不同或个数不同)的实现

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample07

{

classProgram

{

classBaseClass

{

publicvirtualvoidF()

{

Console.WriteLine("BaseClass.F");

}

}

classDeriveClass:BaseClass

{

publicoverridevoidF()

{

base.F();

Console.WriteLine("DeriveClass.F");

}

publicvoidAdd(intLeft,intRight)

{

Console.WriteLine("AddforInt:{0}",Left+Right);

}

publicvoidAdd(doubleLeft,doubleRight)

{

Console.WriteLine("Addforint:{0}",Left+Right);

}

}

staticvoidMain(string[]args)

{

DeriveClasstmpObj=newDeriveClass();

tmpObj.F();

tmpObj.Add(1,2);

tmpObj.Add(1.1,2.2);


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
BaseClass.F
DeriveClass.F
AddforInt:3
Addforint:3.3

8.什么是索引指示器?

答:

实现索引指示器(indexer)的类可以象数组那样使用其实例后的对象,但与数组不同的是索引指示器的参数类型不仅限于int

简单来说,其本质就是一个含参数属性

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample08

{

publicclassPoint

{

privatedoublex,y;

publicPoint(doubleX,doubleY)

{

x=X;

y=Y;

}

//重写ToString方法方便输出

publicoverridestringToString()

{

returnString.Format("X:{0},Y:{1}",x,y);

}

}

publicclassPoints

{

Point[]points;

publicPoints(Point[]Points)

{

points=Points;

}

publicintPointNumber

{

get

{

returnpoints.Length;

}

}

//实现索引访问器

publicPointthis[intIndex]

{

get

{

returnpoints[Index];

}

}

}


//感谢watsonhua(http://huazhihao.cnblogs.com/)的指点

//索引指示器的实质是含参属性,参数并不只限于int

classWeatherOfWeek

{

publicstringthis[intIndex]

{

get

{

//注意case段使用return直接返回所以不需要break

switch(Index)

{

case0:

{

return"Todayiscloudy!";

}

case5:

{

return"Todayisthundershower!";

}

default:

{

return"Todayisfine!";

}

}

}

}

publicstringthis[stringDay]

{

get

{

stringTodayWeather=null;

//switch的标准写法

switch(Day)

{

case"Sunday":

{

TodayWeather="Todayiscloudy!";

break;

}

case"Friday":

{

TodayWeather="Todayisthundershower!";

break;

}

default:

{

TodayWeather="Todayisfine!";

break;

}

}

returnTodayWeather;

}

}

}

classProgram

{

staticvoidMain(string[]args)

{

Point[]tmpPoints=newPoint[10];

for(inti=0;i<tmpPoints.Length;i++)

{

tmpPoints[i]=newPoint(i,Math.Sin(i));

}


PointstmpObj=newPoints(tmpPoints);

for(inti=0;i<tmpObj.PointNumber;i++)

{

Console.WriteLine(tmpObj[i]);

}



string[]Week=newstring[]{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Staurday"};

WeatherOfWeektmpWeatherOfWeek=newWeatherOfWeek();

for(inti=0;i<6;i++)

{

Console.WriteLine(tmpWeatherOfWeek[i]);

}

foreach(stringtmpDayinWeek)

{

Console.WriteLine(tmpWeatherOfWeek[tmpDay]);

}


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre{   font-size:small;   color:black;   font-family:consolas,"CourierNew",courier,monospace;   background-color:#ffffff;   /*white-space:pre;*/}.csharpcodepre{margin:0em;}.csharpcode.rem{color:#008000;}.csharpcode.kwrd{color:#0000ff;}.csharpcode.str{color:#006080;}.csharpcode.op{color:#0000c0;}.csharpcode.preproc{color:#cc6633;}.csharpcode.asp{background-color:#ffff00;}.csharpcode.html{color:#800000;}.csharpcode.attr{color:#ff0000;}.csharpcode.alt{   background-color:#f4f4f4;   width:100%;   margin:0em;}.csharpcode.lnum{color:#606060;}
结果:
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
Todayiscloudy!
Todayisfine!
Todayisfine!
Todayisfine!
Todayisfine!
Todayisthundershower!
Todayiscloudy!
Todayisfine!
Todayisfine!
Todayisfine!
Todayisfine!
Todayisthundershower!
Todayisfine!

9.new修饰符是起什么作用?

答:

new修饰符与new操作符是两个概念

new修饰符用于声明类或类的成员,表示隐藏了基类中同名的成员。而new操作符用于实例化一个类型

new修饰符只能用于继承类,一般用于弥补基类设计的不足

new修饰符和override修饰符不可同时用在一个成员上,因为这两个修饰符在含义上互相排斥

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample09

{

classBaseClass

{

//基类设计者声明了一个PI的公共变量,方便进行运算

publicstaticdoublePI=3.1415;

}

classDervieClass:BaseClass

{

//继承类发现该变量的值不能满足运算精度,于是可以通过new修饰符显式隐藏基类中的声明

publicnewstaticdoublePI=3.1415926;

}

classProgram

{

staticvoidMain(string[]args)

{

Console.WriteLine(BaseClass.PI);

Console.WriteLine(DervieClass.PI);


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
3.1415
3.1415926

10.this关键字的含义?

答:

this是一个保留字,仅限于构造函数和方法成员中使用

在类的构造函数中出现表示对正在构造的对象本身的引用,在类的方法中出现表示对调用该方法的对象的引用,在结构的构造上函数中出现表示对正在构造的结构的引用,在结构的方法中出现表示对调用该方法的结果的引用

this保留字不能用于静态成员的实现里,因为这时对象或结构并未实例化

在C#系统中,this实际上是一个常量,所以不能使用this++这样的运算

this保留字一般用于限定同名的隐藏成员、将对象本身做为参数、声明索引访问器、判断传入参数的对象是否为本身

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample10

{

classClass1

{

privatedoublec;

privatestringvalue;


publicdoubleC

{

get

{

returnc;

}

}

publicClass1(doublec)

{

//限定同名的隐藏成员

this.c=c;

}

publicClass1(Class1value)

{

//用对象本身实例化自己没有意义

if(this!=value)

{

c=value.C;

}

}

publicoverridestringToString()

{

//将对象本身做为参数

returnstring.Format("{0}Celsius={1}Fahrenheit",c,UnitTransClass.C2F(this));

}


//由于好奇,在这做了一个效率测试,想看看到底哪种方式访问成员变量更快,结论:区别不大。。。

publicstringTest1()

{

longvTickCount=Environment.TickCount;

for(inti=0;i<10000000;i++)

this.value=i.ToString();

returnstring.Format("Havethis.:{0}MSEL",Environment.TickCount-vTickCount);

}

publicstringTest2()

{

longvTickCount=Environment.TickCount;

for(inti=0;i<10000000;i++)

value=i.ToString();

returnstring.Format("Don'thavethis.:{0}MSEL",Environment.TickCount-vTickCount);

}

}

classUnitTransClass

{

publicstaticdoubleC2F(Class1value)

{

//摄氏到华氏的转换公式

return1.8*value.C+32;

}

}

classProgram

{

staticvoidMain(string[]args)

{

Class1tmpObj=newClass1(37.5);


Console.WriteLine(tmpObj);


Console.WriteLine(tmpObj.Test1());

Console.WriteLine(tmpObj.Test2());


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
37.5Celsius=99.5Fahrenheit
Havethis.:4375MSEL
Don'thavethis.:4406MSEL

11.可以使用抽象函数重写基类中的虚函数吗?

答:

可以

需使用new修饰符显式声明,表示隐藏了基类中该函数的实现

或增加override修饰符,表示抽象重写了基类中该函数的实现

示例:

classBaseClass

{

publicvirtualvoidF()

{

Console.WriteLine("BaseClass.F");

}

}

abstractclassDeriveClass1:BaseClass

{

publicabstractnewvoidF();

}


//感谢watsonhua(http://huazhihao.cnblogs.com/)的指点

//是他提醒了我还可以用这种方法抽象重写基类的虚方法

abstractclassDeriveClass2:BaseClass

{

publicabstractoverridevoidF();

}


.csharpcode,.csharpcodepre{   font-size:small;   color:black;   font-family:consolas,"CourierNew",courier,monospace;   background-color:#ffffff;   /*white-space:pre;*/}.csharpcodepre{margin:0em;}.csharpcode.rem{color:#008000;}.csharpcode.kwrd{color:#0000ff;}.csharpcode.str{color:#006080;}.csharpcode.op{color:#0000c0;}.csharpcode.preproc{color:#cc6633;}.csharpcode.asp{background-color:#ffff00;}.csharpcode.html{color:#800000;}.csharpcode.attr{color:#ff0000;}.csharpcode.alt{   background-color:#f4f4f4;   width:100%;   margin:0em;}.csharpcode.lnum{color:#606060;}

12.密封类可以有虚函数吗?

答:

可以,基类中的虚函数将隐式的转化为非虚函数,但密封类本身不能再增加新的虚函数

示例:

classBaseClass

{

publicvirtualvoidF()

{

Console.WriteLine("BaseClass.F");

}

}

sealedclassDeriveClass:BaseClass

{

//基类中的虚函数F被隐式的转化为非虚函数


//密封类中不能再声明新的虚函数G

//publicvirtualvoidG()

//{

//Console.WriteLine("DeriveClass.G");

//}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

13.什么是属性访问器?

答:

属性访问器(PropertyAccessor),包括get访问器和set访问器分别用于字段的读写操作

其设计目的主要是为了实现面向对象(OO)中的封装思想。根据该思想,字段最好设为private,一个精巧的类最好不要直接把字段设为公有提供给客户调用端直接访问

另外要注意属性本身并不一定和字段相联系

14.abstract可以和virtual一起使用吗?可以和override一起使用吗?

答:

abstract修饰符不可以和static、virtual修饰符一起使用

abstract修饰符可以和override一起使用,参见第11点

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample14

{

classBaseClass

{

publicvirtualvoidF()

{

Console.WriteLine("BaseClass.F");

}

}

abstractclassDeriveClass1:BaseClass

{

//在这里,abstract是可以和override一起使用的

publicabstractoverridevoidF();

}

classProgram

{

staticvoidMain(string[]args)

{

}

}

}


.csharpcode,.csharpcodepre{   font-size:small;   color:black;   font-family:consolas,"CourierNew",courier,monospace;   background-color:#ffffff;   /*white-space:pre;*/}.csharpcodepre{margin:0em;}.csharpcode.rem{color:#008000;}.csharpcode.kwrd{color:#0000ff;}.csharpcode.str{color:#006080;}.csharpcode.op{color:#0000c0;}.csharpcode.preproc{color:#cc6633;}.csharpcode.asp{background-color:#ffff00;}.csharpcode.html{color:#800000;}.csharpcode.attr{color:#ff0000;}.csharpcode.alt{   background-color:#f4f4f4;   width:100%;   margin:0em;}.csharpcode.lnum{color:#606060;}

15.接口可以包含哪些成员?

答:

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

16.类和结构的区别?

答:
类:


类是引用类型在堆上分配,类的实例进行赋值只是复制了引用,都指向同一段实际对象分配的内存

类有构造和析构函数

类可以继承和被继承

结构:

结构是值类型在栈上分配(虽然栈的访问速度比较堆要快,但栈的资源有限放),结构的赋值将分配产生一个新的对象。

结构没有构造函数,但可以添加。结构没有析构函数

结构不可以继承自另一个结构或被继承,但和类一样可以继承自接口

示例:

根据以上比较,我们可以得出一些轻量级的对象最好使用结构,但数据量大或有复杂处理逻辑对象最好使用类。

如:Geoemtry(GIS里的一个概论,在OGC标准里有定义)最好使用类,而Geometry中点的成员最好使用结构

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample16

{

interfaceIPoint

{

doubleX

{

get;

set;

}

doubleY

{

get;

set;

}

doubleZ

{

get;

set;

}

}

//结构也可以从接口继承

structPoint:IPoint

{

privatedoublex,y,z;

//结构也可以增加构造函数

publicPoint(doubleX,doubleY,doubleZ)

{

this.x=X;

this.y=Y;

this.z=Z;

}

publicdoubleX

{

get{returnx;}

set{x=value;}

}

publicdoubleY

{

get{returnx;}

set{x=value;}

}

publicdoubleZ

{

get{returnx;}

set{x=value;}

}

}

//在此简化了点状Geometry的设计,实际产品中还包含Project(坐标变换)等复杂操作

classPointGeometry

{

privatePointvalue;


publicPointGeometry(doubleX,doubleY,doubleZ)

{

value=newPoint(X,Y,Z);

}

publicPointGeometry(Pointvalue)

{

//结构的赋值将分配新的内存

this.value=value;

}

publicdoubleX

{

get{returnvalue.X;}

set{this.value.X=value;}

}

publicdoubleY

{

get{returnvalue.Y;}

set{this.value.Y=value;}

}

publicdoubleZ

{

get{returnvalue.Z;}

set{this.value.Z=value;}

}

publicstaticPointGeometryoperator+(PointGeometryLeft,PointGeometryRigth)

{

returnnewPointGeometry(Left.X+Rigth.X,Left.Y+Rigth.Y,Left.Z+Rigth.Z);

}

publicoverridestringToString()

{

returnstring.Format("X:{0},Y:{1},Z:{2}",value.X,value.Y,value.Z);

}

}

classProgram

{

staticvoidMain(string[]args)

{

PointtmpPoint=newPoint(1,2,3);


PointGeometrytmpPG1=newPointGeometry(tmpPoint);

PointGeometrytmpPG2=newPointGeometry(tmpPoint);

tmpPG2.X=4;

tmpPG2.Y=5;

tmpPG2.Z=6;


//由于结构是值类型,tmpPG1和tmpPG2的坐标并不一样

Console.WriteLine(tmpPG1);

Console.WriteLine(tmpPG2);


//由于类是引用类型,对tmpPG1坐标修改后影响到了tmpPG3

PointGeometrytmpPG3=tmpPG1;

tmpPG1.X=7;

tmpPG1.Y=8;

tmpPG1.Z=9;

Console.WriteLine(tmpPG1);

Console.WriteLine(tmpPG3);


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
X:1,Y:2,Z:3
X:4,Y:5,Z:6
X:7,Y:8,Z:9
X:7,Y:8,Z:9

17.接口的多继承会带来哪些问题?

答:

C#中的接口与类不同,可以使用多继承,即一个子接口可以有多个父接口。但如果两个父成员具有同名的成员,就产生了二义性(这也正是C#中类取消了多继承的原因之一),这时在实现时最好使用显式的声明

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample17

{

classProgram

{

//一个完整的接口声明示例

interfaceIExample

{

//属性

stringP

{

get;

set;

}

//方法

stringF(intValue);

//事件

eventEventHandlerE;

//索引指示器

stringthis[intIndex]

{

get;

set;

}

}

interfaceIA

{

intCount{get;set;}

}

interfaceIB

{

intCount();

}

//IC接口从IA和IB多重继承

interfaceIC:IA,IB

{

}

classC:IC

{

privateintcount=100;

//显式声明实现IA接口中的Count属性

intIA.Count

{

get{return100;}

set{count=value;}

}

//显式声明实现IB接口中的Count方法

intIB.Count()

{

returncount*count;

}

}

staticvoidMain(string[]args)

{

CtmpObj=newC();


//调用时也要显式转换

Console.WriteLine("Countproperty:{0}",((IA)tmpObj).Count);

Console.WriteLine("Countfunction:{0}",((IB)tmpObj).Count());


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
Countproperty:100
Countfunction:10000

18.抽象类和接口的区别?

答:

抽象类(abstractclass)可以包含功能定义和实现,接口(interface)只能包含功能定义

抽象类是从一系列相关对象中抽象出来的概念,因此反映的是事物的内部共性;接口是为了满足外部调用而定义的一个功能约定,因此反映的是事物的外部特性

分析对象,提炼内部共性形成抽象类,用以表示对象本质,即“是什么”

为外部提供调用或功能需要扩充时优先使用接口

19.别名指示符是什么?

答:

通过别名指示符我们可以为某个类型起一个别名

主要用于解决两个命名空间内有同名类型的冲突或避免使用冗余的命名空间

别名指示符在所有命名空间最外层定义,作用域为整个单元文件。如果定义在某个命名空间内,那么它只在直接隶属的命名空间内起作用

示例:

Class1.cs:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespacecom.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01

{

classClass1

{

publicoverridestringToString()

{

return"com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01'sClass1";

}

}

}


.csharpcode,.csharpcodepre{   font-size:small;   color:black;   font-family:consolas,"CourierNew",courier,monospace;   background-color:#ffffff;   /*white-space:pre;*/}.csharpcodepre{margin:0em;}.csharpcode.rem{color:#008000;}.csharpcode.kwrd{color:#0000ff;}.csharpcode.str{color:#006080;}.csharpcode.op{color:#0000c0;}.csharpcode.preproc{color:#cc6633;}.csharpcode.asp{background-color:#ffff00;}.csharpcode.html{color:#800000;}.csharpcode.attr{color:#ff0000;}.csharpcode.alt{   background-color:#f4f4f4;   width:100%;   margin:0em;}.csharpcode.lnum{color:#606060;}
Class2.cs:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespacecom.nblogs.reonlyrun.CSharp25QExample.Example19.Lib02

{

classClass1

{

publicoverridestringToString()

{

return"com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib02'sClass1";

}

}

}


.csharpcode,.csharpcodepre{   font-size:small;   color:black;   font-family:consolas,"CourierNew",courier,monospace;   background-color:#ffffff;   /*white-space:pre;*/}.csharpcodepre{margin:0em;}.csharpcode.rem{color:#008000;}.csharpcode.kwrd{color:#0000ff;}.csharpcode.str{color:#006080;}.csharpcode.op{color:#0000c0;}.csharpcode.preproc{color:#cc6633;}.csharpcode.asp{background-color:#ffff00;}.csharpcode.html{color:#800000;}.csharpcode.attr{color:#ff0000;}.csharpcode.alt{   background-color:#f4f4f4;   width:100%;   margin:0em;}.csharpcode.lnum{color:#606060;}
主单元(Program.cs):

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


//使用别名指示符解决同名类型的冲突

//在所有命名空间最外层定义,作用域为整个单元文件

usingLib01Class1=com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01.Class1;

usingLib02Class2=com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib02.Class1;


namespaceExample19

{

namespaceTest1

{

//Test1Class1在Test1命名空间内定义,作用域仅在Test1之内

usingTest1Class1=com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01.Class1;


classClass1

{

//Lib01Class1和Lib02Class2在这可以正常使用

Lib01Class1tmpObj1=newLib01Class1();

Lib02Class2tmpObj2=newLib02Class2();

//TestClass1在这可以正常使用

Test1Class1tmpObj3=newTest1Class1();

}

}

namespaceTest2

{

usingTest1Class2=com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01.Class1;


classProgram

{

staticvoidMain(string[]args)

{

//Lib01Class1和Lib02Class2在这可以正常使用

Lib01Class1tmpObj1=newLib01Class1();

Lib02Class2tmpObj2=newLib02Class2();


//注意这里,TestClass1在这不可以正常使用。

//因为,在Test2命名空间内不能使用Test1命名空间定义的别名

//Test1Class1tmpObj3=newTest1Class1();


//TestClass2在这可以正常使用

Test1Class2tmpObj3=newTest1Class2();


Console.WriteLine(tmpObj1);

Console.WriteLine(tmpObj2);

Console.WriteLine(tmpObj3);


Console.ReadLine();

}

}

}

}


.csharpcode,.csharpcodepre{   font-size:small;   color:black;   font-family:consolas,"CourierNew",courier,monospace;   background-color:#ffffff;   /*white-space:pre;*/}.csharpcodepre{margin:0em;}.csharpcode.rem{color:#008000;}.csharpcode.kwrd{color:#0000ff;}.csharpcode.str{color:#006080;}.csharpcode.op{color:#0000c0;}.csharpcode.preproc{color:#cc6633;}.csharpcode.asp{background-color:#ffff00;}.csharpcode.html{color:#800000;}.csharpcode.attr{color:#ff0000;}.csharpcode.alt{   background-color:#f4f4f4;   width:100%;   margin:0em;}.csharpcode.lnum{color:#606060;}
结果:

com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01'sClass1
com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib02'sClass1
com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01'sClass1

20.如何手工释放资源?

答:

.NET平台在内存管理方面提供了GC(GarbageCollection),负责自动释放托管资源和内存回收的工作。但在以下两种情况需要我们手工进行资源释放:一、由于它无法对非托管资源进行释放,所以我们必须自己提供方法来释放对象内分配的非托管资源,比如你在对象的实现代码中使用了一个COM对象;二、你的类在运行是会产生大量实例(象GIS中的Geometry),必须自己手工释放这些资源以提高程序的运行效率

最理想的办法是通过实现一个接口显式的提供给客户调用端手工释放对象,System命名空间内有一个IDisposable接口,拿来做这事非常合适,省得我们自己再声明一个接口了
示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample20

{

classProgram

{

classClass1:IDisposable

{

//析构函数,编译后变成protectedvoidFinalize(),GC会在回收对象前会调用调用该方法

~Class1()

{

Dispose(false);

}


//通过实现该接口,客户可以显式地释放对象,而不需要等待GC来释放资源,据说那样会降低效率

voidIDisposable.Dispose()

{

Dispose(true);

}


//将释放非托管资源设计成一个虚函数,提供在继承类中释放基类的资源的能力

protectedvirtualvoidReleaseUnmanageResources()

{

//Dosomething...

}


//私有函数用以释放非托管资源

privatevoidDispose(booldisposing)

{

ReleaseUnmanageResources();


//为true时表示是客户显式调用了释放函数,需通知GC不要再调用对象的Finalize方法

//为false时肯定是GC调用了对象的Finalize方法,所以没有必要再告诉GC你不要调用我的Finalize方法啦

if(disposing)

{

GC.SuppressFinalize(this);

}

}

}

staticvoidMain(string[]args)

{

//tmpObj1没有手工释放资源,就等着GC来慢慢的释放它吧

Class1tmpObj1=newClass1();


//tmpObj2调用了Dispose方法,传说比等着GC来释放它效率要调一些

//个人认为是因为要逐个对象的查看其元数据,以确认是否实现了Dispose方法吧

//当然最重要的是我们可以自己确定释放的时间以节省内存,优化程序运行效率

Class1tmpObj2=newClass1();

((IDisposable)tmpObj2).Dispose();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

21.P/Invoke是什么?

答:

在受控代码与非受控代码进行交互时会产生一个事务(transition),这通常发生在使用平台调用服务(PlatformInvocationServices),即P/Invoke

如调用系统的API或与COM对象打交道,通过System.Runtime.InteropServices命名空间

虽然使用Interop非常方便,但据估计每次调用事务都要执行10到40条指令,算起来开销也不少,所以我们要尽量少调用事务

如果非用不可,建议本着一次调用执行多个动作,而不是多次调用每次只执行少量动作的原则

22.StringBuilder和String的区别?

答:

String在进行运算时(如赋值、拼接等)会产生一个新的实例,而StringBuilder则不会。所以在大量字符串拼接或频繁对某一字符串进行操作时最好使用StringBuilder,不要使用String

另外,对于String我们不得不多说几句:

1.它是引用类型,在堆上分配内存

2.运算时会产生一个新的实例

3.String对象一旦生成不可改变(Immutable)

3.定义相等运算符(==!=)是为了比较String对象(而不是引用)的值

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample22

{

classProgram

{

staticvoidMain(string[]args)

{

constintcycle=10000;


longvTickCount=Environment.TickCount;

Stringstr=null;

for(inti=0;i<cycle;i++)

str+=i.ToString();

Console.WriteLine("String:{0}MSEL",Environment.TickCount-vTickCount);


vTickCount=Environment.TickCount;

//看到这个变量名我就生气,奇怪为什么大家都使它呢?:)

StringBuildersb=newStringBuilder();

for(inti=0;i<cycle;i++)

sb.Append(i);

Console.WriteLine("StringBuilder:{0}MSEL",Environment.TickCount-vTickCount);


stringtmpStr1="A";

stringtmpStr2=tmpStr1;

Console.WriteLine(tmpStr1);

Console.WriteLine(tmpStr2);

//注意后面的输出结果,tmpStr1的值改变并未影响到tmpStr2的值

tmpStr1="B";

Console.WriteLine(tmpStr1);

Console.WriteLine(tmpStr2);


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre{   font-size:small;   color:black;   font-family:consolas,"CourierNew",courier,monospace;   background-color:#ffffff;   /*white-space:pre;*/}.csharpcodepre{margin:0em;}.csharpcode.rem{color:#008000;}.csharpcode.kwrd{color:#0000ff;}.csharpcode.str{color:#006080;}.csharpcode.op{color:#0000c0;}.csharpcode.preproc{color:#cc6633;}.csharpcode.asp{background-color:#ffff00;}.csharpcode.html{color:#800000;}.csharpcode.attr{color:#ff0000;}.csharpcode.alt{   background-color:#f4f4f4;   width:100%;   margin:0em;}.csharpcode.lnum{color:#606060;}
结果:
String:375MSEL
StringBuilder:16MSEL
A
A
B
A

23.explicit和implicit的含义?

答:

explicit和implicit属于转换运算符,如用这两者可以让我们自定义的类型支持相互交换

explicti表示显式转换,如从A->B必须进行强制类型转换(B=(B)A)

implicit表示隐式转换,如从B->A只需直接赋值(A=B)

隐式转换可以让我们的代码看上去更漂亮、更简洁易懂,所以最好多使用implicit运算符。不过!如果对象本身在转换时会损失一些信息(如精度),那么我们只能使用explicit运算符,以便在编译期就能警告客户调用端

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample23

{

classProgram

{

//本例灵感来源于大话西游经典台词“神仙?妖怪?”--主要是我实在想不出什么好例子了

classImmortal

{

publicstringname;

publicImmortal(stringName)

{

name=Name;

}

publicstaticimplicitoperatorMonster(Immortalvalue)

{

returnnewMonster(value.name+":神仙变妖怪?偷偷下凡即可。。。");

}

}

classMonster

{

publicstringname;

publicMonster(stringName)

{

name=Name;

}

publicstaticexplicitoperatorImmortal(Monstervalue)

{

returnnewImmortal(value.name+":妖怪想当神仙?再去修炼五百年!");

}

}

staticvoidMain(string[]args)

{

ImmortaltmpImmortal=newImmortal("紫霞仙子");

//隐式转换

MonstertmpObj1=tmpImmortal;

Console.WriteLine(tmpObj1.name);


MonstertmpMonster=newMonster("孙悟空");

//显式转换

ImmortaltmpObj2=(Immortal)tmpMonster;

Console.WriteLine(tmpObj2.name);


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
紫霞仙子:神仙变妖怪?偷偷下凡即可。。。
孙悟空:妖怪想当神仙?再去修炼五百年!


24.params有什么用?


答:

params关键字在方法成员的参数列表中使用,为该方法提供了参数个数可变的能力

它在只能出现一次并且不能在其后再有参数定义,之前可以

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceConsoleApplication1

{

classApp

{

//第一个参数必须是整型,但后面的参数个数是可变的。

//而且由于定的是object数组,所有的数据类型都可以做为参数传入

publicstaticvoidUseParams(intid,paramsobject[]list)

{

Console.WriteLine(id);

for(inti=0;i<list.Length;i++)

{

Console.WriteLine(list[i]);

}

}


staticvoidMain()

{

//可变参数部分传入了三个参数,都是字符串类型

UseParams(1,"a","b","c");

//可变参数部分传入了四个参数,分别为字符串、整数、浮点数和双精度浮点数数组

UseParams(2,"d",100,33.33,newdouble[]{1.1,2.2});


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
1
a
b
c
2
d
100
33.33
System.Double[]


25.什么是反射?


答:

反射,Reflection,通过它我们可以在运行时获得各种信息,如程序集、模块、类型、字段、属性、方法和事件

通过对类型动态实例化后,还可以对其执行操作

简单来说就是用string可以在runtime为所欲为的东西,实际上就是一个.netframework内建的万能工厂

一般用于插件式框架程序和设计模式的实现,当然反射是一种手段可以充分发挥其能量来完成你想做的任何事情(前面好象见过一位高人用反射调用一个官方类库中未说明的函数。。。)

示例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


namespaceExample25Lib

{

publicclassClass1

{

privatestringname;

privateintage;


//如果显式的声明了无参数构造函数,客户端只需要用程序集的CreateInstance即可实例化该类

//在此特意不实现,以便在客户调用端体现构造函数的反射实现

//publicClass1()

//{

//}

publicClass1(stringName,intAge)

{

name=Name;

age=Age;

}

publicvoidChangeName(stringNewName)

{

name=NewName;

}

publicvoidChangeAge(intNewAge)

{

age=NewAge;

}

publicoverridestringToString()

{

returnstring.Format("Name:{0},Age:{1}",name,age);

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
反射实例化对象并调用其方法,属性和事件的反射调用略去

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;


//注意添加该反射的命名空间

usingSystem.Reflection;


namespaceExample25

{

classProgram

{

staticvoidMain(string[]args)

{

//加载程序集

AssemblytmpAss=Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory+"Example25Lib.dll");


//遍历程序集内所有的类型,并实例化

Type[]tmpTypes=tmpAss.GetTypes();

foreach(TypetmpTypeintmpTypes)

{

//获取第一个类型的构造函数信息

ConstructorInfo[]tmpConsInfos=tmpType.GetConstructors();

foreach(ConstructorInfotmpConsInfointmpConsInfos)

{

//为构造函数生成调用的参数集合

ParameterInfo[]tmpParamInfos=tmpConsInfo.GetParameters();

object[]tmpParams=newobject[tmpParamInfos.Length];

for(inti=0;i<tmpParamInfos.Length;i++)

{

tmpParams[i]=tmpAss.CreateInstance(tmpParamInfos[i].ParameterType.FullName);

if(tmpParamInfos[i].ParameterType.FullName=="System.String")

{

tmpParams[i]="Clark";

}

}


//实例化对象

objecttmpObj=tmpConsInfo.Invoke(tmpParams);

Console.WriteLine(tmpObj);


//获取所有方法并执行

foreach(MethodInfotmpMethodintmpType.GetMethods())

{

//为方法的调用创建参数集合

tmpParamInfos=tmpMethod.GetParameters();

tmpParams=newobject[tmpParamInfos.Length];

for(inti=0;i<tmpParamInfos.Length;i++)

{

tmpParams[i]=tmpAss.CreateInstance(tmpParamInfos[i].ParameterType.FullName);

if(tmpParamInfos[i].ParameterType.FullName=="System.String")

{

tmpParams[i]="ClarkZheng";

}

if(tmpParamInfos[i].ParameterType.FullName=="System.Int32")

{

tmpParams[i]=27;

}

}

tmpMethod.Invoke(tmpObj,tmpParams);

}


//调用完方法后再次打印对象,比较结果

Console.WriteLine(tmpObj);

}

}


Console.ReadLine();

}

}

}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
结果:
Name:Clark,Age:0
Name:ClarkZheng,Age:27

示例下载:http://www.cnblogs.com/Files/reonlyrun/CSharp25QExample07.rar

如果你认为还有哪些概念比较重要或容易混淆,可以在回复中提出,我会及时更新这篇随笔



一些话:

To:watsonhua,谢谢你帮我改正了第4、11、14和19点的错误,并且让我对索引指示器的理解更全面!

To:xiao,谢谢你关于“实例化”的详细解释,让这篇随笔中的措词更加精确!

To:charleschen,谢谢你追问,让第1、第8的提法更恰当!

To:装配脑袋,谢谢你提供internalprotected含义的正确答案!

本贴子以“现状”提供且没有任何担保,同时也没有授予任何权利
Thispostingisprovided"ASIS"withnowarranties,andconfersnorights.

postedon2007-04-0513:44ClarkZheng阅读(10799)评论(108)编辑收藏引用网摘所属分类:A..NET



//Sys.WebForms.PageRequestManager._initialize('AjaxHolder$scriptmanager1',document.getElementById('Form1'));
Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tAjaxHolder$UpdatePanel1'],[],[],90);
//]]>

评论:

#re:C#基础概念二十五问2007-04-0513:54|亚历山大同志

[align=left]很重要的基础概念,每个C#的开发人员都应该弄明白先,不过......回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0513:58|亚历山大同志

[align=left]还有,我很喜欢用sb,呵呵,个人作品,公司的东西还是严格按照公司规范来回复更多评论
[/align]

#C#基础概念二十五问[TrackBack]2007-04-0514:07|CDplayer

[align=left]C#基础概念二十五问注:本文部份资料来自网络,如有侵权,请与我联系,我会在第一时间声明引用或将其删除!查看原文回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0514:09|非我

[align=left]我先自测了一遍,按100分算只能打80+,惭愧……回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0514:24|随风流月

[align=left]什么时候做个VisualBasic的测验?
这些东西基本都看不懂,除了一些CLR共通的……回复更多评论
[/align]

#C#基础概念二十五问[TrackBack]2007-04-0514:50|Sean(陈阳)

[align=left]C#基础概念二十五问注:本文部份资料来自网络,如有侵权,请与我联系,我会在第一时间声明引用或将其删除!查看原文回复更多评论
[/align]

#re:C#基础概念二十五问[未登录]2007-04-0514:56|fly_bluewolf

[align=left]还有"unbox"和"box"这两个概念,很容易被人忽略.回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0515:23|ClarkZheng

[align=left]@亚历山大同志
:)回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0515:24|ClarkZheng

[align=left]@非我
不要以偶的参考答案评分,里面可能错误多多呢回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0515:24|ClarkZheng

[align=left]@随风流月
我不会推出VB.NET的版本了,如果感兴趣,你可以写一个?回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0515:26|ClarkZheng

[align=left]@fly_bluewolf
关于装箱和拆箱。。。我再看看吧,个人感觉真的没什么好写的回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0515:45|波→ONLINE

[align=left]不错,不错。收藏了。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0516:01|装配脑袋

[align=left]@随风流月
如果想要VB的话……

1.静态变量和非静态变量的区别?
2.Const和SharedReadonly区别?
3.Declare是什么意思?
4.MustInherit/MustOverride是什么意思?
5.Friend修饰符起什么作用?
6.NotInheritable/NotOverridable修饰符是干什么的?
7.Overrides和Overloads的区别?
8.什么是默认属性?
9.Shadows修饰符是起什么作用?
10.Me关键字的含义?
11.可以使用抽象函数重写基类中的虚函数吗?(答案与C#不同)
12.不可继承类可以有虚函数吗?
13.如果基类中的虚属性只有一个属性访问器,那么继承类重写该属性后可以有几个属性访问器?如果基类中有Get和Set两个呢?(答案与C#不同)
14.MustOverride可以和Overridable一起使用吗?可以和Overrides一起使用吗?
15.接口可以包含哪些成员?
16.类和结构体的区别?
17.接口的多继承会带来哪些问题?
18.抽象类和接口的区别?
19.Global关键字是什么?
20.如何释放非托管资源?
21.P/Invoke是什么?
22.StringBuilder和String的区别?
23.Narrowing和Widening的含义?
24.ParamArray有什么用?
25.什么是反射?回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0516:22|charleschen

[align=left]不错的文章,
追问:
静态方法和普通方法的区别?
显示接口与隐式接口的区别?
为什么要使用Get/Set而不是直接操作类成员?
GC释放资源有哪几种方法?回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0516:56|HuacnLee

[align=left]不错的文章
以前看着这些名词都不知道什么意思,其实自已一直在用,呵呵回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0516:57|HuacnLee

[align=left]我来回答@charleschen
用Get/Set因为是可以独立设置只写或只能写吧回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0517:19|DflyingChen

[align=left]@装配脑袋
真厉害…………人工翻译阿回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0517:24|流浪的狗

[align=left]汗...我连及格都不行.
基础太差.回复更多评论
[/align]

#C#基础概念二十五问[TrackBack]2007-04-0517:33|俺喜欢打篮球

[align=left]C#基础概念二十五问查看原文回复更多评论
[/align]

#re:C#基础概念二十五问[未登录]2007-04-0517:40|没剑

[align=left]override表示重载,用于同一个类中同名方法不同参数(包括类型不同或个数不同)的实现
------------
这里的override应为overload回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0519:01|ClarkZheng

[align=left]@装配脑袋
汗,真是C#.NET和VB.NET同时精通的人才呀。。。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0519:04|ClarkZheng

[align=left]@没剑
感谢你的细心,正文已修正!回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0520:01|Aの扬凡

[align=left]是一次做复习的机会回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0521:16|戴眼镜的太阳

[align=left]呵呵,不错,学了不少,用C#写了一段时间的程序了,但是你里面的东西我还有好多没用过,继续研究C#:)回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0521:18|郭志坚

[align=left]嗯,不错,基本上都清楚这些概念.
这一年没白混,呵呵回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0521:18|BolerGuo

[align=left]很好很好,图文并茂。11、12还是有点儿迷惑,主要是new,virtual,abstract,sealed这几个概念容易混淆~回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0521:35|ClarkZheng

[align=left]@charleschen

1.静态方法和普通方法的区别?
答:静态方法是通过类型调用,在对象未实例化前就可以使用,因此在其实现中不能使用非静态的成员(如:非静态的变量、非静态的方法)

2.显式接口和隐式接口?
答:你是指显式接口成员吗?

3.为什么要使用Get/Set而不是直接操作类成员?
答:get/set是C#为实现属性而设计的访问器,提出这概念主要是为了实现OO中的“封装”。根据该思想,字段最好设为private,一个精巧的类最好不要直接把字段设为公有提供给客户调用端直接访问
另外,在设计模式中提到如果你有一个public的方法,那么最好再设计一个protected的虚函数以方便子类中对该方法进行扩展,属性访问器的设计可以让我们完成该模式,不是吗?

4.GC释放资源有哪几种方法?
答:我不太理解这个题目,你想问什么呢?GC释放资源的流程?

以上回答还希望大家多多提意见,确认比较全面并且无误后,我会加到随笔正文
回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0521:52|ClarkZheng

[align=left]@BolerGuo
new比较特殊,这个关键字既是修饰符又是运算符,做为运算符时用于实例化类型,做为修饰符时,请参照第9点的答案

sealed起密封作用,意味该类型或成员不会再有继承,所以虚函数会自动变成非虚函数。非函数在CLR查找其实现时速度会快一点,这也是我提到sealed有时可以提高程序运行效率的原因

virtual没什么好说的吧,虚函数OO中多态的基础呀

abstract请参照第4点的答案回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0521:58|watsonhua

[align=left]大体上正确,但不精确,建议参照框架设计,说的深入一些。
还有一些个人看法,不算纠正,只算补充。
索引指示器实质是含参属性,也就是说,它的参数不限于int,把它比作数组未免...
可以使用抽象函数重写基类中的虚函数吗?这个问题我觉得楼主理解有一些问题,不需要加new修饰。所谓abstract,new,virtual只是虚函数的版本元数据的几个向量而已,当然你也可以把那个函数理解为new的,但这个new不是atttribute,而是函数的元数据里的一个标志位。所以你即便不加new修饰,编译器也不会报warning。
其他还有几个地方用词也值得斟酌。
算然已经很好了,但我们应该有更高的目标。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0522:00|watsonhua

[align=left]@ClarkZheng
quote"静态方法是通过类型调用,在类未实例时就可以使用"
类事例化前是不能使用的,我想你的意思应该是对象实例化前吧。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0522:14|lavy

[align=left]关于THIS的用法
限定被相似的名称隐藏的成员,例如:

publicEmployee(stringname,stringalias)
{
this.name=name;
this.alias=alias;
}

我有疑问:
什么是被相似的名称隐藏的成员??
相似指什么?什么时候会出现隐藏?回复更多评论
[/align]

#re:C#基础概念二十五问[未登录]2007-04-0522:51|小鬼

[align=left]真强,我一直想做这么一件事情,可一直都没有做,谢谢你为我提供了这么好的快速复习小册子。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0523:23|ClarkZheng

[align=left]@watsonhua
谢谢你关于索引指示器的讲解,正文我已修订,并将示例更新了

关于”使用抽象函数重写基类中的虚函数“,如果不加new修饰符编译时会给警告。你可以把Example11示例中,DeriveClass的F函数去掉new修饰符,然后编译试一下

关于类实例化和对象实例化,我还是听从了你的意见,上面的回复也已改正

ps:非常希望你能帮其它几处用词不当的地方指出,我们就是应该有更高的目标!回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0523:30|ClarkZheng

[align=left]@lavy
我的原文是”this保留字一般用于限定同名的隐藏成员、将对象本身做为参数、声明索引访问器、判断传入参数的对象是否为本身“,并没有”限定被相似的名称隐藏的成员“

针对第一个用处,我再详细说明一下:

//正确,由于类本身的变量c和构造函数的参数c重名,这时就需要使用this显式指出是将参数的c赋值给类的变量c
privatedoublec;
publicClass1(doublec)
{
//限定同名的隐藏成员
this.c=c;
}

//错误,会给出一个警告:对同一变量赋值。编译器没有看到我们实际想赋值的成员变量c,所以我们称它”隐藏“了
privatedoublec;
publicClass1(doublec)
{
c=c;
}
回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0523:36|ClarkZheng

[align=left]@HuacnLee
@Aの扬凡
@戴眼镜的太阳
@郭志坚
@BolerGuo
@小鬼
谢谢你们的支持!回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0600:08|watsonhua

[align=left]@ClarkZheng
能够严肃的讨论技术实在是人生快事。
11.可以使用抽象函数重写基类中的虚函数吗?
不知这个重写是override还是overload,还是重名函数就算。
若是override,当然是可以的,但不要忘了加override修饰,编译器推倒不出的。
若是overload,当然是可以的,但凡不写new,是要抛warning的。
回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0600:26|ClarkZheng

[align=left]@watsonhua
本文把overload译为重载,把override译为重写,请参见第7点答案

我的问题是抽象函数(abstract)是否可以重写(override)基类中的虚函数,而abstract和override修饰符是不可以同时使用的,会产生二义性,所以谈不上把override忘了

出本题的目的缘于我在引用一个类库时发现其中一个基类设计不合理,仅仅设为虚函数(virtual)并没有设成抽象函数(abstract)--具体情况这里略去。所以我想把它改成抽象函数,以便使用我的类库的开发人员如果继承该类必须强制性的重写(override)该函数。So,我碰到了一个警告,通过增加new修饰符解决了该问题。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0601:02|watsonhua

[align=left]usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;

namespaceExample11
{
classBaseClass
{
publicvirtualvoidF()
{
Console.WriteLine("BaseClass.F");
}
}
abstractclassDeriveClass:BaseClass
{
publicabstractoverridevoidF();
}
classProgram
{
staticvoidMain(string[]args)
{
}
}
}
试一下吧回复更多评论
[/align]

#(保存)C#基础概念二十五问[TrackBack]2007-04-0601:13|nasa

[align=left]C#基础概念二十五问注:本文部份资料来自网络,如有侵权,请与我联系,我会在第一时间声明引用或将其删除!查看原文回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0601:55|ClarkZheng

[align=left]@watsonhua
请原谅我的浅见拙识,原文中已改正了所有关于abstract和override关系的地方,下载文件也已替换。
在此只好是”再次“感谢你了:)回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0603:36|watsonhua

[align=left]再补充一点我的理解吧,我觉得@ClarkZheng的这篇文章写得相当用心,也足见@ClarkZheng做人,做程序员的责任心。
1.静态变量和非静态变量的区别?
静态变量在类实例化时创建,非静态变量在对象实例化时创建,
即静态变量在类构造函数调用的时候创建,非静态变量在对象构造函数调用时创建。
@ClarkZheng的sample里用的是一个可以使用一条语句就可以完成创建的静态变量,所以掩盖了这个问题。
@ClarkZheng说静态变量是类被装载时创建的,我不清楚他说的类被装载是什么时候。
assembly被装载到appdomain时是不会的,类在被使用前的一瞬,会调用静态构造函数完成类的实例化。
2.const和staticreadonly区别?
完全正确,不再补充。
3.extern是什么意思?
不知道存不存在其他功能,如cpp里的extern"C"。
4.abstract是什么意思?
6.sealed修饰符是干什么的?
7.override和overload的区别?
http://www.cnblogs.com/huazhihao/archive/2007/04/06/702083.html可以参考这篇。
5.internal修饰符起什么作用?
没什么好说的,搞清楚和protected的区别就可以了,当然internalprotected的语意是internal&&protected
8.什么是索引指示器?
已经补充过了。
9.new修饰符是起什么作用?
不是很喜欢这种关键词重载。
10.this关键字的含义?
this很好理解。java里可以使用对象访问类属属性,相比起来,更喜欢c#里的设计。
11.可以使用抽象函数重写基类中的虚函数吗?
讨论过,答案是可以。absolutely。
12.密封类可以有虚函数吗?
问题是"密封类可以有虚函数吗",结果回答的是"密封类的父类可以有虚函数"。照clark兄的意思是密封类可以包含虚的成员方法,我觉这个问题问得没有意义。sealed的类最起码是object的派生类,object有ToString(),答案是明显的。
13.如果基类中的虚属性只有一个属性访问器,那么继承类重写该属性后可以有几个属性访问器?如果基类中有get和set两个呢?
属性的实质是方法,若有一个virtual方法自然可以override。所以,派生类可以override父类的get,只要父类有get,set同理。
quote"如果基类中的虚属性只有一个属性访问器,那么继承类重写该属性后也应只有一个。如果基类中有get和set两个属性访问器,那么继承类中可以只有一个也可以同时有两个属性访问器".@clarkzhang表述的不够准确。
14.abstract可以和virtual一起使用吗?可以和override一起使用吗?
参见http://www.cnblogs.com/huazhihao/archive/2007/04/06/702083.html
15.接口可以包含哪些成员?
interface可以包含所有的可以被继承且可以被派生类实例化的成员,并且interface自己不能被实例化。interface遵照此原则。因为比较宽松,所以才会出现范型接口这种病态的但又不可或缺的东西。
16.类和结构的区别?
class和struct的区别再不交互时是很容易辨认的,当class里有struct,struct里又有class就很热闹了。
class和struct的比较重要的问题是,eqauls方法和原型方法的逻辑。当class里有struct,或struct里有class,不能靠object.equals了,既要考虑怎样重用父类里的equals,又要考虑便于派生类拓展,怎么样才算equals,非常复杂。而原型方法就是(iclonable).clone,深的还是浅的,多深多浅,要结合equals方法考虑。当然不要忘了重载==。
再提一句,stuctA{}的实质是classA:System.ValueType{},但是这个System.ValueType是一个class。想来有趣,有一点像夏娃,是用亚当的一根肋骨做程的。
17.接口的多继承会带来哪些问题?
这个问题改成"多接口的继承会带来哪些问题?"比较好。@clarkzhang解释的还是正确的,只要不造成二义性,可以不用显示转型。
18.抽象类和接口的区别?
抽象类的原则是存在不可以被实例化的方法的类,接口的原则前面提到过。
19.别名指示符是什么?
using的一个作用,作用范围是using的所在名空间内,并且在using的语句后面。并非只在一个单元文件内起作用。
当然别名像多接口继承一样,也是要"去二义化"的。
20.如何释放非托管资源?
问题改成"如何强制释放资源"比较好。
不建议强制释放资源,除非逼不得已。gc,人间凶器阿...
21.P/Invoke是什么?
没怎么用过,不敢发表意见。
22.StringBuilder和String的区别?
区别还是很大的。倒是string和值类型的近似行为更值得讲解。
另外cycle=100000还是少一到两个零比较好,意思一下就好了么。
23.explicit和implicit的含义?
例子很形象。Explicit存在的意义相当于c++里的拷贝构造函数。
24.params有什么用?

publicstaticvoidUseParams(intid,paramsobject[]list)
{
Console.WriteLine(id);
for(inti=0;i<list.Length;i++)
{
Console.WriteLine(list[i]);
}
}
...
UseParams(2,"d",100,33.33,newdouble[]{1.1,2.2});
最后会输出System.Double[]是因为cw((object)o)的逻辑是cw(o.ToString()),而(object).ToString()默认输出(object).GetType().ToString()
params的实质是一个ParamArrayAttribute,因为c#不支持默认参数,所以不定秩的形参只有靠它来。对比c++,可读性无疑增强了。c++里好像也有vlist...的东西,名称记不得了,好像还要加一个头文件,用起来非常麻烦,还不可以做编译期的类型检查。不过c#里没有默认参数,如果要和vb,c++交互的话,要用Type.Missing来补空位,不可以用null。曾经调用office的com,一个函数里用了40个Type.Missing,无语啊。
25.什么是反射?
用string可以在runtime为所欲为的东西。实际上就是一个.netframework内建的万能工厂。
结:
这里的大部分问题的讨论结果已经不能算是基础概念了,而是底层概念了,希望能对大家有帮助。如果有不足的地方还请大家补充,如果我有理解错误的地方还请多指教。
回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0604:44|ClarkZheng

[align=left]@watsonhua
关于”类实例化“和”对象实例化“,有没有更好的说法?我一直表达不清楚两个概念,请教一下这两个词的”完美“程度如何?

关于extern,本文只讨论C#语言范畴,前面有说

internalprotected的语意是internal&&protected,perfect!

关于第12题,密封类可以有虚函数吗?你的这个object举得非常恰当,我也感觉这个问题没有意义了。。。

索引指示器的实质是带参属性、属性的实质是方法,佩服你的见解
偶再补充一句:事件的实质是属性

关于第19题,我的试验结果是只在一个单元文件内起作用

关于第20题我觉得你的提法比我强

关于cycle=100000,不知道是不是偶的机器太过强悍,少一个零后,输出结果如下:(我只是想让第二个不是0呀,另外特别声明一个常量做为循环次数就是方便各位朋友修改,不是我编码风格有多好。。。)
String:343MSEL
StringBuilder:0MSEL

ps:偶的名字是ClarkZheng,不是@ClarkZheng。:)回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0608:38|ddr888

[align=left]Attribute重要不?回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0608:47|watson

[align=left]不错,很详细~回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0609:28|Sephil

[align=left]@watsonhua
voidwriteError(interr,...)
{
va_listvaList;
va_start(vaList,err);
//yourcodehere
va_end(vaList);
}回复更多评论
[/align]

#re:C#基础概念二十五问[未登录]2007-04-0610:05|天下

[align=left]@watsonhua
静态变量在类实例化时创建,非静态变量在对象实例化时创建--没明白这句话的意思。

我想对象实例化就是通过new来调用构造器吧

那什么叫类实例化呢?回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0610:13|ClarkZheng

[align=left]@ddr888
嗯,很重要,不过按这种一回一答的方式好象不容易写好。
我考虑一下,正好把那个第12题换掉回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0610:50|天龙之吻

[align=left]signed:)回复更多评论
[/align]

#re:C#基础概念二十五问[未登录]2007-04-0610:52|xiao

[align=left]@天下
类实例化指的是调用类的静态构造器,一个类只能有一个无参无修饰符的静态构造器,它只能调用一次,用于初始化类中静态字段的状态
对象实例化指的是调用通常意义上的构造器,它用于创建类的一个具体实例,这种构造器一个类中可以有多个重载版本
代码如下:
sealedclassXiao{
privatestaticstringstr;
//此为类构造器,可查看IL,其中编译为cctor
staticXiao()
{
str="qpppp";
}
//此为实例构造器,可查看IL,其中编译为ctor
publicXiao()
{
//当然实例构造器也能作用于静态字段
str="eeeeeeeeeee";
}
}回复更多评论
[/align]

#[收藏]C#基础概念二十五问[TrackBack]2007-04-0610:57|天龙之吻

[align=left]//滚动子标题varmarqueeContent=newArray();marqueeContent[0]='真心感谢我的老婆';marqueeContent...查看原文回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0611:03|lavy

[align=left]@ClarkZheng
this"限定被相似的名称隐藏的成员"
是MSDN的解释:)
你的解释,我懂了!~谢谢!回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0611:11|watsonhua

[align=left]@ClarkZheng
类实例化和对象实例化xiao兄已经举例,不赘述。最初听到类实例化是在李建忠老师那里,我的理解也是建立在他翻译的applied.netframeworkprogramming,这里的问题书上都有讲道。
谢谢Sephil兄,帮我复习一下久违的c++,怀念...
关于第19题,我说的语气没表述出来。我的语气是带一点反话的。我的意思是using只在它所在的名空间内有用,换而言之,如果单个文件有多个嵌套名空间,using只在它所直接隶属的名空间内可用。当然,如果它没有放在名空间内的话,作用域就是整个文件了。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0611:17|ClarkZheng

[align=left]@lavy
MSDN。。。不是忘看了就是看了忘记了,谢谢你的提醒回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0611:22|watsonhua

[align=left]@ClarkZheng
clark兄,关于称呼抱歉抱歉。:)我有的地方是直接粘的。
这篇post貌似verypopular。
clark兄可以整理一下,再置顶于个人主页上,长期讨论...
当然欢迎clark兄就其他技术问题作讨论。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0612:17|ClarkZheng

[align=left]@xiao
感谢,正文已修改回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0613:07|ClarkZheng

[align=left]@watsonhua
改了第20题的提法
改了第22题的内容和示例,增加了对String的解释

示例下载已更新回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0613:38|ClarkZheng

[align=left]@charleschen
你的追问中关于静态函数与非静态函数的问题,我已在第1题中做了修改
关于属性访问器的用处,也已在第8题中做了修改

其它两个问题我还不能理解题面的意思,期待着你的回复回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0613:49|yunhuasheng

[align=left]楼主挺认真的!!;)回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0614:26|想飞的猪

[align=left]支持LZ,让俺重温了一遍....回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0614:31|装配脑袋

[align=left]internalprotected的语意应该是internal|protected,而不是internal&&protected。相信不少没有用过的老手也不知道。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0614:58|阿齐

[align=left]类实例化指的是把一个类实例化的过程,即把类的静态成员初始化的过程;
而对象实例化,就是构造一个该类的实例,然后初始化该实例的实例成员回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0615:38|装配脑袋

[align=left]我尝试从这些语法的最直接效果作答这些问题:

1.静态成员和非静态成员的区别?
静态字段为类型所有实例所共享,而实例字段则为每个对象实例所专有。
静态方法不能访问实例成员,而且无需对象实例即可调用。
静态构造方法仅在AppDomain初始化类型时执行一次,而且具有AppDomain级别的线程安全性。而实例构造函数则在对象初始化时执行。

2.const和staticreadonly区别?
const的字段在编译时会将其字面值直接写到引用它的地方,而且必须用字面常量在编译时初始化。
staticreadonly可以在运行时初始化。

3.extern是什么意思?
extern表示函数体在其他地方定义。因此这样的函数只有声明没有定义。

4.abstract是什么意思?
abstract用于类表示该类不能实例化,用于成员表示它是子类必须重写的过程。

5.internal修饰符起什么作用?
表示该类型或成员仅在同一程序集中可被其他类型所访问。

6.sealed修饰符是干什么的?
表示该类型不能被继承,或该(虚拟)成员不能再被子类所重写。

7.override和overload的区别?
我其实不太愿意讨论两个范畴的东西有什么区别,因为硬要说区别就等于把两者的定义分别写一遍。

8.什么是索引指示器?
是一种带参数的属性,通过obj[params]的语法进行调用。

9.new修饰符是起什么作用?
它指示该过程在MethodTable中开启一个新的“slot”,从而断开基类同名虚成员对其的调用关系。

10.this关键字的含义?
在引用类型中,它表示所调用的对象实例的引用。在值类型中,它是一个符号,将this上的各种操作转嫁给所调用的值类型对象实例。

11.可以使用抽象函数重写基类中的虚函数吗?
当且仅当基类中相应的函数也为抽象函数。

12.密封类可以有虚函数吗?
可以,甚至有些封闭类带有新声明的虚函数(所有委托类型)。

13.什么是属性访问器?
使用访问变量的语法访问属性时,实际被调用的过程。

14.abstract可以和virtual一起使用吗?可以和override一起使用吗?
可以和override一起使用,当且仅当重写一个父类的虚成员时。

15.接口可以包含哪些成员?
接口仅可以包含过程,即方法、属性、事件。而且只能定义过程的签名,不能定义他们的方法体、访问级别等。

16.类和结构的区别?
类为引用类型
结构为值类型
结构没有终结器
结构不能继承
结构必须有一个默认构造方法,且不能自定义无参数构造方法
结构的成员不能在声明时赋值
结构默认有专门实现的不同==和GetHashCode方法

17.接口的多继承会带来哪些问题?
任何特性均在正确使用时发挥正确的效果。因此我们应该看到多继承的优势。

18.抽象类和接口的区别?
抽象类可以有构造方法
抽象类可以有终结器
抽象类可以有字段
抽象类可以有静态成员
抽象类可以没有抽象方法
抽象类可以有实例方法
一个类只能继承一个抽象类,而可以实现多个接口
抽象类的成员可以带有访问性级别
抽象类之间不能多继承,接口则可以
抽象类可以有静态构造方法

19.别名指示符是什么?
命名空间别名限定符::专名用来限定所用的名字要从指定别名所表示的范围开始搜索。别名为extern或using关键字定义的命名空间或根别名。

20.如何手工释放资源?
没有手工释放托管资源的功能,尽管有些看其来是在释放其实不是。只能手工释放非托管资源。

21.P/Invoke是什么?
通过Runtime进行封送(Marshal),调用公开方式的非托管代码,包括DLL和COM等。

22.StringBuilder和String的区别?
基本上是写出两者定义的那种“区别”

23.explicit和implicit的含义?
这是两个类型转换运算符,explicit运算符需要明确指出目标类型名,而implicit会根据上下文自动调用。

24.params有什么用?
一种提供参数数目可变的参数传递方法。任意数目的参数可转化为一个数组。

25.什么是反射?
通过程序基内的元数据和Runtime的支持在运行时读取程序集、模块、类型和成员的信息,以及在运行时通过这种途径访问对象的成员或执行对象的方法。甚至动态改变类型和方法的组成。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0616:02|ClarkZheng

[align=left]@装配脑袋
感谢你精心的回答,让我受益菲浅,之所以没有使用这种“最直接的效果”来做答案也许是为了让一些人看得更明白,也许是因为我的语言组织能力没有这么强。:)
真心希望你能将你的回答写成随笔,让我有机会在正文中将这些回答做为引用,方便大家更全面的了解这些概念。

ps:关于internalprotected的语意能不能详细讨论一下?如果这里不方便可以通过MSN与我联系,谢谢!回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0616:05|ClarkZheng

[align=left]@watson
@Sephil
@天龙之吻
@yunhuasheng
@想飞的猪
@阿齐
谢谢你们的支持!
回复更多评论
[/align]

#C#基础概念二十五问(转)[TrackBack]2007-04-0616:18|eric.123

[align=left]C#基础概念二十五问注:本文部份资料来自网络,如有侵权,请与我联系,我会在第一时间声明引用或将其删除!查看原文回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0616:47|装配脑袋

[align=left]internalprotected其实很简单,只是看字面意思容易弄错。许多人认为internalprotected应该是“只有同一个程序集中的子类可以访问”的意思,但其实不是这样的。internalprotected表示“同一个程序集中的所有类,以及所有程序集中的子类都可以访问”。也就是说是“protected或internal”的访问级别。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0618:34|watsonhua

[align=left]@装配脑袋
我记错了。谢谢。internalprotected是protected或internal回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0702:02|ClarkZheng

[align=left]@装配脑袋
在第5点的答案里增加了对internalprotected的解释,谢谢你的指点!

示例下载地址也已更新回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0720:51|大豆男生

[align=left]收藏回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0721:53|ClarkZheng

[align=left]@大豆男生
谢谢支持回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0721:54|ClarkZheng

[align=left]@watsonhua
关于第19题,别名指示符的作用域已调整

示例下载地址已更新回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0821:15|heqing

[align=left]great!,butIhaveaproblem.
declareattributefieldabove:

abstractpublicStringAttribute
{
get;
}

whynot
abstractpublicstringAttribute
{
get;
}

回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0822:04|玉开

[align=left]这篇随便的质量很高,谢谢楼主回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0910:40|ClarkZheng

[align=left]@heqing
"stringisanaliasforStringinthe.NETFramework"--MSDN
So,ifreetousebothoftheminmycode...回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0910:41|ClarkZheng

[align=left]@玉开
谢谢
回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0910:58|http://salonliudong.cnblogs.com

[align=left]第9个问题.程序中第二行注释中的“显示”应该是“显式”,从第11个问题的答案中可以看出
第22个问题答案第三点String对象一量生成不可改变,是不是一旦生成不可改变回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-0912:19|ClarkZheng

[align=left]@http://salonliudong.cnblogs.com
谢谢你的细心,正文和示例下载都已修正。回复更多评论
[/align]

#re:C#基础概念二十五问[未登录]2007-04-0918:12|小莫

[align=left]比较有价值的贴,顶一下。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-1213:14|金色海洋(jyk)

[align=left]能不能说一下委托、事件、异步、多线程的知识呢?回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-1213:33|ClarkZheng

[align=left]@金色海洋(jyk)
委托和事件在以上二十五里的示例里用了很多,通过看这些代码应该能有所理解
关于多线程,我只做过简单的研究,请参照我的另一篇随笔
http://www.cnblogs.com/reonlyrun/archive/2006/12/26/640993.html回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-1310:08|森林

[align=left]在子类中,重写有什么作用啊?回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-1313:38|ClarkZheng

[align=left]@森林
扩展或修改继承的方法、属性、索引器或事件的抽象实现或虚实现

面向对象编程里多态的实现手段回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-2014:39|清晨风

[align=left]终于看完了,还有几处不懂,没基础啦,过几天再看一遍.
非常感谢,~_~回复更多评论
[/align]

#re:C#基础概念二十五问[未登录]2007-04-2311:42|ZhuZhu

[align=left]ApplicationBlock是什么?SqlHelper?回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-2411:09|拔掉内存

[align=left]你好!关于你的第十四个问题的例子,你把DeriveClass1类定义成abstract,但又继承了BaseClass,这样可以吗?DeriveClass1类可以理解成基类,但又去继承别的类?你能解释一下吗?回复更多评论
[/align]

#C#基础概念二十五问[TrackBack]2007-04-2514:38|mbskys

[align=left]http://www.cnblogs.com/reonlyrun/archive/2007/04/05/CSharp_25_Question.html注:本文部份资料来自网络,如有侵权,请与我联系...查看原文回复更多评论
[/align]

#re:C#基础概念二十五问[未登录]2007-04-2522:40|Thanks

[align=left]非常感谢!
不过,说真的,楼主,不知道是你的表达能力太差还是其实你自己也没理解透,感觉很多地方表述不清楚或者不准确,例子也写得不好。
还是装配脑袋强,几句话,说的清楚明了。
回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-2614:57|Hunts.C

[align=left]Mark:)回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-2710:43|Jz

[align=left]类被实例化是什么意思?
也就是说创建类的对象吗?如果是这样第一点就有点小问题咯。回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-2817:58|ClarkZheng

[align=left]@Thanks
虚心接受您的批评,我在写这篇随笔时是尽自己的努力来完成的,如果有哪些不清楚地方请指出来,我会进一步改进,包括例子,让以后看到这篇随笔的朋友可以更容易理解回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-2817:59|ClarkZheng

[align=left]@Jz
类被实例化和对象被实例化是两个概念,有区别的。看一下回复记录也许你就能明白了回复更多评论
[/align]

#re:C#基础概念二十五问2007-04-2818:22|ClarkZheng

[align=left]@拔掉内存
抽象类也可以继承自其它类,在这个例子中我主要是为了体现“abstract是可以和override一起使用的”,而只有一个类中有抽象方法这个类就必须被声明为抽象类回复更多评论
[/align]

#re:C#基础概念二十五问2007-05-0621:06|IDreamer

[align=left]表达的的确不太好,特别是有的例子不够好。不过这种学习方法很好,我正在学java也是这样进行的。顺便说一下,java真是一个混乱的语言,平台和语法都混乱,比起来可爱的C#我们要知足了,ms真不愧是王中之王。

thanks,lz,学习回复更多评论
[/align]

#C#基礎二十五問(轉)[TrackBack]2007-05-0711:47|Ammy

[align=left]http://www.cnblogs.com/reonlyrun/archive/2007/04/05/CSharp_25_Question.html查看原文回复更多评论
[/align]

#re:C#基础概念二十五问2007-05-0811:08|mgdn.com.cn

[align=left]基本上是IT公司是C#面试题,呵呵回复更多评论
[/align]

#re:C#基础概念二十五问2007-05-0909:52|tqj

[align=left]继承接口中的有的方法编译时怎么说
修饰符“virtual”对该项无效
修饰符“public”对该项无效
呢请指点

回复更多评论
[/align]

#re:C#基础概念二十五问2007-05-1009:29|清晨风

[align=left]在msdn上看到这样一段话"静态成员在第一次被访问之前并且在任何静态构造函数(如调用的话)之前初始化"(网址:http://msdn2.microsoft.com/zh-cn/library/79b3xss3(VS.80).aspx),我测试过,好象只有静态字段才是这样的,其他静态成员如静态属性都是在静态构造函数之后才初始化的,不知是不是我理解有问题,请楼主帮忙解释一下.
我用的测试类如下:
publicsealedclassSingleton
{
staticSingletoninstance=null;
Singleton()
{
}
staticSingleton()
{
}
publicstaticSingletonInstance
{
get
{
if(instance==null)
{
instance=newSingleton();
}
returninstance;
}
}
}
回复更多评论
[/align]

#C#基础概念二十五问-ClarkZheng-博客园[TrackBack]2007-05-1114:33|JoeyLiang

[align=left]回复更多评论
[/align]

#re:C#基础概念二十五问2007-05-1611:12|BoatBoy

[align=left]@装配脑袋
11.可以使用抽象函数重写基类中的虚函数吗?
当且仅当基类中相应的函数也为抽象函数。

怎么感觉和ClarkZheng的文章有出入呢?
看原文的14条,抽象函数重写了基类的虚函数,但是基类中的函数好像不是抽象的吧。

另外
7.override和overload的区别?
我其实不太愿意讨论两个范畴的东西有什么区别,因为硬要说区别就等于把两者的定义分别写一遍。

这里我觉得两者应该不是绝然不同的两个东西,想想多态的概念两者都是对多态的实现。不过一个是在类内部,一个在继承类之间而已。

请指教。回复更多评论
[/align]

#re:C#基础概念二十五问2007-05-2116:57|winnerzone

[align=left]还真没有好好注意这些问题过.回复更多评论
[/align]

#[导入]C#基础概念二十五问[TrackBack]2007-05-2313:22|希望虫

[align=left]当初学C#时是找个人大概问了一下数据类型和分支语句就开始做项目了。这两天又全面的看了一下相关的基础知识(学而时习之嘛),总结了25个问题:1.静态变量和非静态变量的区别?2.const...查看原文回复更多评论
[/align]

#re:C#基础概念二十五问2007-05-3020:25|刘阿大

[align=left]我认为关于静态的表述有点问题----“类的实例化时创建”应该表述为“类在第一次实例化时”;关于非静态变量的“在对象实例化时创建”就更有问题,对象本身就是实例化后的产物。
还有关于this的说法我觉得会让初学者误解,“在类的方法中出现表示对调用该方法的对象的引用”,其实我们知道不是这样,this代表被调用的类.回复更多评论
[/align]

#re:C#基础概念二十五问[未登录]2007-06-0623:09|SWP

[align=left]支持.....真强

我是什么都不会的初学者对我很有用谢咯回复更多评论
[/align]

#re:C#基础概念二十五问2007-06-1114:22|VB客

[align=left]感觉还是vb.net的语义描述比较清晰易懂,所以我还是坚持使用vb而没有转向c#,建议初学者还是从vb.net入手比较好,因为在.net中,两种编程语言的功能上的差别几乎可以忽略了,除非想搞些更底层的东西.
回复更多评论
[/align]

#re:C#基础概念二十五问[未登录]2007-06-1500:08|JAY

[align=left]好家伙../
谢拉回复更多评论
[/align]

#re:C#基础概念二十五问2007-06-2015:09|2008kou

[align=left]structPoint:IPoint
{
privatedoublex,y,z;
//结构也可以增加构造函数
publicPoint(doubleX,doubleY,doubleZ)
{
this.x=X;
this.y=Y;
this.z=Z;
}
publicdoubleX
{
get{returnx;}
set{x=value;}
}
publicdoubleY
{
get{returnx;}
set{x=value;}
}
publicdoubleZ
{
get{returnx;}
set{x=value;}
}
}
X:1,Y:1,Z:1
X:6,Y:6,Z:6
X:9,Y:9,Z:9
X:9,Y:9,Z:9
structPoint:IPoint
{
privatedoublex,y,z;
//结构也可以增加构造函数
publicPoint(doubleX,doubleY,doubleZ)
{
this.x=X;
this.y=Y;
this.z=Z;
}
publicdoubleX
{
get{returnx;}
set{x=value;}
}
publicdoubleY
{
get{returny;}
set{y=value;}
}
publicdoubleZ
{
get{returnz;}
set{z=value;}
}
}

X:1,Y:2,Z:3
X:4,Y:5,Z:6
X:7,Y:8,Z:9
X:7,Y:8,Z:9
[/align]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: