嵌套类型
在类或结构内部定义的类型称为嵌套类型。例如:
class Container
{
class Nested
{
Nested() { }
}
}
不管外部类型是类还是结构,嵌套类型均默认为private,但是可以设置为public、protected internal、protected、internal或private。在上面的示例中,Nested对外部类型是不可访问的,但可以设置为public,如下所示:
class Container
{
public class Nested
{
Nested() { }
}
}
嵌套类型(或内部类型)可访问包含类型(或外部类型)。若要访问包含类型,请将其作为构造函数传递给嵌套类型。例如:
public class Container
{
public class Nested
{
private Container m_parent;
public Nested()
{
}
public Nested(Container parent)
{
m_parent = parent;
}
}
}
嵌套类型可访问包含类型的私有成员和受保护的成员(包括所有继承的私有成员或受保护的成员)。
在前面的声明中,类Nested的完整名称为Container.Nested。这是用来创建嵌套类的新实例的名称,如下所示:
Container.Nested nest = new Container.Nested();
访问修饰符
可以限制类和结构,以便只有声明它们的程序或命名控件才能使用它们。可以限制类成员,以便只有派生类才能使用它们,或者限制类成员,以便只有当前命名控件或程序中的类才能使用它们。访问修饰符是添加到类、结构或成员声明的关键字,用以指定这些限制。这些关键字包括public、private、protected和internal。例如:
public class Bicycle
{
public void Pedal() { }
}
类和结构的可访问性
没有嵌套在其他类或结构中的类和结构可以是公共的,也可以是内部的。声明为公共的类型可由任何其他类型访问。声明为内部的类型只能由同一程序集中的类型访问。类和结构默认声明为内部的,除非向类定义添加了关键字public,如前面的示例所示。类或结构定义可以添加internal关键字,使其访问级别称为显式的。访问修饰符不影响类或结构自身--它始终能偶访问自身及其所有成员。
类成员和结构成员的可访问性
可以使用五种访问类型之一--来声明类成员或结构成员。与类和结构自身一样,它们也可以是公共的或内部的。可以使用protected关键字将类成员声明为受保护的,意味着只有使用该类作为基类的派生类型才能访问该成员。通过组合protected和internal关键字,可以将类成员标记为受保护的内部成员--只有派生类型或同一程序集中的类型才能访问该成员。最后,可以使用private关键字将类成员或结构成员声明为私有的,指示只有声明该成员的类或结构才能访问该成员。
// public class:
public class Tricycle
{
// protected method:
protected void Pedal() { }
// private field:
private int m_wheels = 3;
// protected internal property:
protected internal int Wheels
{
get { return m_wheels; }
}
}
其他类型
与类一样,接口也可声明为公共类型或内部类型。与类不同,接口默认具有内部访问级别。接口成员始终是公共的,不能应用任何访问修饰符。
命名空间和枚举成员始终是公共的,不能应用任何访问修饰符。
委托默认具有内部访问级别。
默认情况下,在命名空间中或在编译单元顶部(例如,不在命名空间、类或结构中)声明的任何类型都是内部的,但是可以成为公共的。
分部类定义
可以将类、结构或接口的定义拆分到两个或多个源文件中。每个源文件包含类定义的一部分,编译应用程序时将把所有部分组合起来。在以下几种情况下需要拆分类定义:
l 处理大型项目时,使一个类分布于多个独立文件中可以让多位程序员同时对该类进行处理。
l 使用自动生成的源时,无需重新创建源文件便可将代码添加到类中。Visual Studio在创建Windows窗体、Web服务包装代码等时都使用此方法。无需编辑Visual Studio所创建的文件,便可创建使用这些类的代码。
l 若要拆分定义,请使用partial关键字修饰符,如下所示:
public partial class Employee
{
public void DoWork()
{
}
}
public partial class Employee
{
public void GoToLunch()
{
}
}
备注
使用partial关键字表明可在命名空间内定义该类、结构或接口的其他部分。所有部分都必须使用partial关键字。在编译时,各个部分都必须可用来形成最终的类型。各个部分必须具有相同的可访问性,如public、private等。
如果将任意部分声明为抽象的,则整个类型都被视为抽象的。如果将任意部分声明为密封的,则整个类型都被视为密封的。如果将任意部分声明为基类型,则整个类型都将继承该类。
指定基类的所有部分必须一致,但忽略基类的部分仍继承该基类型。各个部分可以指定不同的基接口,最终类型将实现所有分部声明所列出的全部接口。在某一分部定义中声明的任何类、结构或接口成员可供所有其他部分使用。最终类型是所有部分在编译时的组合。
注意
分部修饰符不可用于委托或枚举声明中。
嵌套类型可以是分部的,即使它们所嵌套于的类型本身并不是分部的也如此。例如:
class Container
{
partial class Nested
{
void Test() { }
}
partial class Nested
{
void Test2() { }
}
}
l 编译时将对分部类型定义的属性进行合并。例如,下面的声明:
[System.SerializableAttribute]
partial class Moon { }
[System.ObsoleteAttribute]
partial class Moon { }
等效于:
[System.SerializableAttribute]
[System.ObsoleteAttribute]
class Moon { }
将从所有分部类型定义中对以下内容进行合并:
l XML注释
l Interfaces
l 泛型类型参数属性
l 类属性
l 成员
例如,下面的声明:
partial class Earth : Planet, IRotate { }
partial class Earth : IRevolve { }
等效于:
class Earth : Planet, IRotate, IRevolve { }
限制
处理分部类定义时需遵循下面的几个规则:
l 要作为同一类型的各个部分的所有分部类型定义都必须使用partial进行修饰。例如,下面的类声明将生成错误:
public partial class A { }
//public class A { } // Error, must also be marked partial
l partial修饰符只能出现在紧靠关键字class、struct或interface前面的位置。
l 分部类型定义中允许使用嵌套的分部类型,例如:
partial class ClassWithNestedClass
{
partial class NestedClass { }
}
partial class ClassWithNestedClass
{
partial class NestedClass { }
}
l 要成为同一类型的各个部分的所有分部类型定义都必须在同一程序集和同一模块(.exe或.dll文件)中进行定义。分部定义不能跨越多个模块。
l 类名和泛型类型参数在所有的分部类型定义中都必须匹配。泛型类型可以是分部的。每个分部声明都必须以相同的顺序使用相同的参数名。
l 下面的用于分部类型定义中的关键字是可选的,但是如果某关键字出现在一个分部类型定义中,则该关键字不能与在同一类型的其他分部定义中指定的关键字冲突:
publit
private
protected
internal
abstract
sealed
基类
new修饰符(嵌套部分)
一般约束
示例
下面的示例在一个分部类定义中声明类CoOrds的字段和构造函数,在另一个分部类定义中声明成员PrintCoOrds。
private int x;
private int y;
public CoOrds(int x,int y){
this.x = x;
this.y = y;
}
}
public partial class CoOrds {
public void PrintCoOrds(){
System.Console.WriteLine("CoOrds: {0},{1}",x,y);
}
}
class TestCoOrds2 {
static void Main(){
CoOrds myCoOrds = new CoOrds(10,15);
myCoOrds.PrintCoOrds();
}
}
示例
从下面的示例可以看出,也可以开发分部结构和接口。
partial interface ITest
{
void Interface_Test();
}
partial interface ITest
{
void Interface_Test2();
}
partial struct S1
{
void Struct_Test() { }
}
partial struct S1
{
void Struct_Test2() { }
}