代码改变世界

CLR via C# 边读边想 06 - 类型和成员基础

2012-06-30 22:56  richardzhaoxb  阅读(143)  评论(0编辑  收藏  举报

The Different Kinds of Type Members

一个类可以定义以下成员:

Constants,常量:经常以类的静态成员存在,提高可维护性和可读性。

Fields,字段:可以是实例字段也可以是类的静态字段。一般字段都是定义为私有的。

  • Instance constructors,实例构造函数。
  • Type constructors,类型构造函数。
  • Methods,方法:用来读取和改写字段的操作。
  • Operator overloads,操作符重写:定义了对象碰到特殊的操作符时的运算方法。因为不是所有的编程语言都支持操作符重写,所以不是 Common Language Specification (CLS) 的内容。
  • Conversion operators,转换操作符:定义如何隐式的和显示的从一个类型转换到另外一个类型。和操作符重写一样,也不是 CLS 支持的。
  • Properties,属性。
  • Events,事件:有静态的事件和实例的事件。
  • Types,内部类。

 

Type Visibility

类型有两种看访问性:public 和 internal。默认情况下,不指定的话,类型是 internal 的。 internal 指只有同一个 assembly 的成员可以访问到。

如果我们指定了 internal 的类型,又想让特定的其他 assembly 访问,可以使用 friend  assembly 特性,在需要被访问的 internal 类型上加上属性:

using System;
using System.Runtime.CompilerServices; // For InternalsVisibleTo attribute
// This assembly's internal types can be accessed by any code written
// in the following two assemblies (regardless of version or culture):
[assembly:InternalsVisibleTo("Wintellect, PublicKey=12345678...90abcdef")]
[assembly:InternalsVisibleTo("Microsoft, PublicKey=b77a5c56...1934e089")]
internal sealed class SomeInternalType { ... }
internal sealed class AnotherInternalType { ... }

 

Member Accessibility

CLR 定义了一套成员访问控制符,但是每一种语言使用的语法有所不同,例如在 CLR 中的 Assembly 控制符,在C#中用的 internal。下面按照公开程度从低到高的顺序列出 6 种不同的访问控制符:

当然成员可访问性要受到成员访问控制符和类型的可访问性的共同影响,比如,在 Assembly A中 的 一个 internal 类型中定义了一个 public 的方法 M1,Assembly B 中的成员也不能访问 M1。

在派生类中,如果重写了基类的方法,也要求使用同样的访问控制符。

 

Static Classes

只有 class 可以是静态的,structure 不可以是静态的,因为值类型必须要生成每一个实例。

编译器对于 静态的 class 有以下的限制:

  • 必须是从 SystemObject 继承。
  • 不能实现任何接口。
  • 只能定义静态成员(字段,方法,属性,事件)。
  • 不能被用作其他类成员的字段,不能作为函数参数,不能作为本地变量。

 

Partial Classes, Structures, and Interfaces

部分类只是 C# 编译器支持的属性,CLR 是根本不知道也不支持部分类的。那么微软设计这样的特性是为了:

  • 版本控制,设想一个类型牵涉到了很多的源代码,一个开发人员把它签出了,其他人就不能同时签出修改。 partial 关键字可以把一个类型分成几个文件让不同的人分别负责修改。
  • 有时候,一个类型提供了比较多的特性,这时可以把每个特性分开在不同的逻辑单元。
  • 为了把机器产生的代码和人写的代码分开,方便维护和更新。

 

Components, Polymorphism, and Versioning

 

How the CLR Calls Virtual Methods, Properties, and Events

现在我们来看看虚方法,同时也来看看虚属性和虚事件,因为属性和事件也是基于方法实现的。

方法是对一个类型进行操作的代码,所有的方法都有一个名字,签名,和返回值。CLR 允许有相同的名字的方法,但是有不同的签名或返回值。但是很多语言都只允许不同的签名,会忽略返回值。

关于 IL 代码的研究,先省去。。。。

 

Using Type Visibility and Member Accessibility Intelligently

sealed 类型比 unsealed 类型好,有三个原因:

  • 如果一个类型初始是 sealed,它还可以在以后把它改为 unsealed 的。 但是如果一开始是 unsealed 的,要想在以后把他改为 sealed,就很可能不能正常编译,因为破坏了它后面的继承关系。
  • JIT 编译器为 sealed 类型/方法 产生的代码具有更好的性能。
  • 有更加严格的安全性,和可预测性。

当然 sealed 的最大的问题就是可扩展性不好。以下是我在设计类型时的参考指南:

  • 当定义一个类型时,我经常是显示的申明它是 sealed ,除非我确定它肯定是一个基类。同样,默认情况下把类型设计为 internal 的,除非知道它肯定要被其他类型引用。
  • 字段永远都是定义为private的。
  • 方法,属性,事件要定义为 private 和 nonvirtual,除非真的需要才定义为 protected or internal,尽可能的少定义 virtual 方法,虽然带来了灵活性,也带来了复杂的继承和多肽,更加依赖于派生类的做出正确的行为。