定义类成员
成员定义
在类定义中,也提供了该类中所有成员的定义,包括域、方法和属性
所有成员都有自己的访问级别:
public:成员可以由任何代码访问
private:成员只能由类中的代码访问(默认)
internal:成员只能由定义它的工程(装配件)内部的代码访问
protected:成员只能由类或派生类中的代码访问
protected internal:成员只能由工程(装配件)中派生类的的代码访问
域、方法和属性都可以使用关键字static来声明,表示静态成员
定义域
域用标准的变量声明格式和前面介绍的修饰符来说明
例如:
class MyClass
{
public int MyInt;
}
注意:公共成员推荐用PascalCasing命名模式,私有成员可以用camelCasing命名模式
域可以使用readonly关键字,表示域只能在只能在执行构造函数的过程中赋值,或由初始化赋值语句赋值
例如:
class MyClass
{
public readonly int MyInt = 17;
}
用static表示静态成员
例如:
class MyClass
{
public static int MyInt;
}
静态域可以通过定义他们的类来访问,而不能通过对象实例来访问
通过const来创建一个常量
const成员也是静态的,不过不需要用static修饰
定义方法
方法使用标准函数格式,以及可访问性和可选的static修饰符来声明
例如:
class MyClass
{
public string GetString()
{
return "Here is a string.";
}
}
注意:如果使用了static就只能通过类来访问
其他关键字
virtual:方法可以重写
abstract:方法必须重写(只用于抽象类)
override:方法重写了一个基类方法
extern:方法定义放在其他地方
例如:
public class MyBaseClass
{
public virtual void DoSomething()
{
// Base implementation.
}
}
public class MyDerivedClass : MyBaseClass
{
public override void DoSomething()
{
// Derived class implementation, overrides base implementation.
}
}
如果使用了override,可以使用sealed指定这个方法不能在派生类中重写
例如:
public class MyDerivedClass : MyBaseClass
{
public override sealed void DoSomething()
{
// Derived class implementation, overrides base implementation.
}
}
使用extern可以提供方法在工程外部使用的代码
定义属性
属性有两个类似于函数的块,一个用于获取属性的值,另一个用于设置属性的值
两个块分别用get和set关键字来定义
可用于控制对属性的访问级别,忽略get块创建只写属性,忽略set块创建只读属性
这只适用于外部代码,因为类中代码可以访问这些块能访问的数据
属性至少包含一个块,才是有效的
属性基本结构包括准访问修饰关键字(public、private等)、后跟类名、属性名和函数块
例如:
public int MyIntProp
{
get
{
// Property get code.
}
set
{
// Property set code.
}
}
Get块必须有一个属性类型的返回值
简单的属性一般与一个私有域相关联,以控制对这个域的访问
例如:
// Field used by property.
private int myInt;
// Property.
public int MyIntProp
{
get
{
return myInt;
}
set
{
// Property set code.
}
}
这样外部代码就必须通过属性来访问这个私有域
Set函数以类似方式把一个值赋給域
可以使用关键字value引用用户提供的属性值
例如:
// Field used by property.
private int myInt;
// Property.
public int MyIntProp
{
get
{
return myInt;
}
set
{
myInt = value;
}
}
value等于与属性的类型向同的值
属性更大的作用在于对操作进行更多的控制
例如:
set
{
if (value >= 0 && value <= 10)
myInt = value;
}
如果使用了无效的值,有四种处理方法:
1 什么也不做(如上例)
2 给域赋默认值
3 继续执行,但记录该事件
4 抛出一个异常
通常使用后面两种
例如:
set
{
if (value >= 0 && value <= 10)
myInt = value;
else
throw (new ArgumentOutOfRangeException("MyIntProp", value, "Error!"));
}
可以在使用属性的代码中通过try...catch...finally来处理
属性可以使用virtual,override和abstract关键字
VS成员向导
在类视图中,显示了工程中定义的类及其成员
成员属性
类成员的其他议题
隐藏基类方法
当继承的成员并不是我们需要的时候,可以把它隐藏掉
例如:
public class MyBaseClass
{
public void DoSomething()
{
//Base implementation
}
}
public class MyDerivedClass:MyBaseClass
{
public void DoSomething()
{
//Derived class implementation,hides base implementation
}
}
这段代码隐藏了基类的DoSomething()方法,能正常运行,但会产生一个警告
如果用new关键字显式声明要隐藏的成员,就不会有警告
例如:
public class MyDerivedClass:MyBaseClass
{
new public void DoSomething()
{
//Derived class implementation,hides base implementation
}
}
注意隐藏和重写的区别
用override重写将会替换基类中的执行代码
而用隐藏的方式将会新建一个方法
即使要隐藏的方法虚拟的,该方法也不会被重写
主要的区别体现在多态中,被重写的成员将写入对象实例,而用于隐藏的代码将不会被写入
例如:
class MyBaseClass
{
public virtual string DoSomething()
{
return "a";
}
}
class MyDerivedClass1 : MyBaseClass
{
public override string DoSomething()
{
return "b";
}
}
class MyDerivedClass2 : MyBaseClass
{
new public string DoSomething()
{
return "b";
}
}
多态
MyBaseClass oA = new MyDerivedClass1();
MyBaseClass oB = new MyDerivedClass2();
结果:
oA.DoSomething()将返回"b",oB.DoSomething()将返回"a"
调用重写或隐藏的基类方法
无论重写成员还是隐藏成员,都可以在类的内部访问基类成员。
使用:
要对派生类隐藏基类的公共成员,但在类中访问其功能
要给继承的虚拟成员添加执行代码,而不只是重写
可以使用base关键字,它表示包含在派生类中的基类的执行代码
例如:
public class MyBaseClass
{
public virtual void DoSomething()
{
//Base implementation
}
}
public class MyDerivedClass:MyBaseClass
{
public void DoSomething()
{
//code
base.DoSomething();
//code
}
}
这里base.DoSomething()包含了基类中的DoSomething()方法的执行代码
base使用对象实例,所以在静态成员中使用
this关键字
与base相似,this也可以用在类成员的内部,也是引用对象实例
由this引用的对象实例是当前的对象实例
嵌套的类型定义
除了在名称空间中定义类之外,还可以在其他类中定义这些类
public class MyClass
{
public class myNestedClass
{
public int nestedClassField;
}
}
要在MyClass外部实例化myNestedClass:
MyClass.myNestedClass myObj = new MyClass.myNestedClass();
接口的执行
定义接口:
interface IMyInterface
{
// Interface members.
}
接口成员:
1 所有接口成员都是公共的,不允许使用访问修饰符
2 接口成员不能包含代码体
3 接口不能定义域成员
4 接口成员不能使用关键字static, virtual, abstract, 或sealed来定义
5 接口不能定义成员类型
要隐藏继承了基接口的成员,可以用new关键字来定义
例如:
interface IMyBaseInterface
{
void DoSomething();
}
interface IMyDerivedInterface : IMyBaseInterface
{
new void DoSomething();
}
执行方式与隐藏继承的类成员一样
在接口中定义属性可以确定服务块get和set能否用于该属性
例如:
interface IMyInterface
{
int MyInt
{
get;
set;
}
}
注意:接口没有指定属性应如何存储,接口不能指定域
接口与类一样可以定义为类的成员
在类中执行接口
执行接口的类必须包含该接口所有成员的执行代码,且必须匹配指定的签名,并且是公共的
可以使用关键字virtual或abstract来执行接口成员,但不能使用static或const
例如:
public interface IMyInterface
{
void DoSomething();
void DoSomethingElse();
}
public class MyClass : IMyInterface
{
public void DoSomething()
{
}
public void DoSomethingElse()
{
}
}
接口成员还可以在基类上执行
例如:
public interface IMyInterface
{
void DoSomething();
void DoSomethingElse();
}
public class MyBaseClass
{
public void DoSomething()
{
}
}
public class MyDerivedClass : MyBaseClass, IMyInterface
{
public void DoSomethingElse()
{
}
}
继承一个执行给定接口的基类,那么派生类隐式地支持这个接口
例如:
public interface IMyInterface
{
void DoSomething();
void DoSomethingElse();
}
public class MyBaseClass : IMyInterface
{
public virtual void DoSomething()
{
}
public virtual void DoSomethingElse()
{
}
}
public class MyDerivedClass : MyBaseClass
{
public override void DoSomething()
{
}
}
注意:如果用隐藏而不是重写,则IMyInterface.DoSomething()将引用基类的方法,即使派生类通过这个接口来访问
显式执行接口成员
接口成员也可以由类显式执行
这时,该成员只能通过接口来访问,不能通过类来访问
例如:
public interface IMyInterface
{
void DoSomething();
void DoSomethingElse();
}
public class MyClass : IMyInterface
{
void IMyInterface.DoSomething()
{
}
public void DoSomethingElse()
{
}
}
其中DoSomething()是显式执行,DoSomethingElse()是隐式执行
对于显式执行的接口成员只能通过接口访问
例如:
IMyInterface myInt = new MyClass();
myInt.DoSomething();
对于隐式执行的接口成员可以通过类或接口来访问:
例如:
MyClass myObj = new MyClass();
myObj.DoSomething();
或者
IMyInterface myInt = new MyClass();
myInt.DoSomething();