第6章类型和成员基础(CLR学习)
类型的各种成员:
1.常量 是指出数据值恒定不变的字符
2.字段 表示只读或可读/可写的数据值。字段也可以是静态的;这种字段被认为是类型状态的一部分;字段也可以是实例(非静态);这种字段被认为是对象状态的一部分。
3.实例构造器 是将新对象实例字段初始化为良好初始状态的特殊方法。
4.类型构造器 是将类型的静态字段初始化为良好初始状态的特殊方法。
5.方法 是更改或查询类型或对象状态的函数
6.操作符重载 定义了当操作符作用于对象时,应该如何操作该对象。
7.转换操作符 定义如何隐式或显示将对象从一种类型转型为另一种类型的方法。
8.属性 允许用简单的.字段风格的语法设置或查询类型或对象的逻辑状态,同时保证状态不被破坏。
9.事件 静态时间允许类型一个或多个静态或实例方法发送通知。实例(非静态)事件允许对象向一个或多个静态或实例方法发送通知。
10.类型 类型可定义其他嵌套类型
类型的可见性
public类型不仅对定义程序集中所有代码可见,还对其他程序集中的代码可见。
internal 类型则仅对定义程序集中所有代码可见
什么事友元程序集;就是internal类型的程序可以在其他程序集可访问;生成程序集时,可用System.Runtime.CompilerServices命名空间中的InternalsVisibkeTo特性标明它可认为是“友元”的程序集。
1.创建一个项目控制台程序
2 在项目ConsoleApp中添加对项目Utility的引用。
3 将项目Utility中的类SomeInternalType访问级别设置为Internal。
namespace Utility { internal class SomeInternalType { public override string ToString() { return string.Format("{0}","开始");; } } }
4 现在在ConsoleApp项目中是肯定不能访问到类SomeInternalType的,如果想让类Program可以访问类SomeInternalType,必须将项目ConsoleApp的程序集添加为项目Utility程序集的友元程序集。添加友元程序集我们要使用InternalIsVisibleTo特性,使用该特性需要添加命名空间
using System.Runtime.CompilerServices。
5 在SomeInternalType类中使用InternalIsVisibleTo特性将程序集ConsoleApp添加为友元程序集。
using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("ConsoleApp")] namespace Utility { internal class SomeInternalType { public override string ToString() { return string.Format("{0}","开始");; } } }
6 InternalIsVisibleTo特性也可以添加到AssemblyInfo.cs中。
7 现在在项目Utility的类SomeInternalType中就可以访问ConsoleApp项目的类Program了。
合理使用类型的可见性和成员的可访问性
三个方面:版本控制,性能,安全性和可预测性
定义类时遵循的原则
1.定义类时,除非确定要将其作为基类,并允许派生类对它进行特化,否则总是显示地指定为Sealed类型。如果真要定义一个可由其它类继承的类,同时不希望允许特化,那么会重写并密封继承的所有虚方法。
2.类的内部,将数据字段定义为私有"private"。
3.在类的内部,将方法,属性和事件定义的顺序为:优先考虑private和非虚,再考虑public,再到protected和internal,最后定义为virtual;因为虚成员会放弃许多控制,丧失独立性,变得彻底依赖于派生类的正确行为。
4.oop有一条古老的格言,大意是当事情变得过于复杂的时,就搞更多的类型出来。当算法的实现开始变得复杂时,定义一些辅助(例如:扩展类等)类型来封装独立的功能。
对类进行版本控制时的虚方法的处理
1,创建两个类基类A和派生类B 如果两个类中都相同的方法和虚拟方法 就需要在派生类方法前面加上new关键字,new关键字告诉编译器生成的元数据,让CLR知道A类型的方法应被视为A类型引入的心函数。
namespace CompayA { public class Phone { public void Dial() { Console.WriteLine("Phone.Dial"); EstablishConnection(); } public virtual void EstablishConnection() { Console.WriteLine("Phone.EstablishConnection"); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CompayB { public class BeeterPhone:CompayA.Phone { public new void Dial() { Console.WriteLine("BeeterPhone.Dial"); EstablishConnection(); base.Dial(); } public new virtual void EstablishConnection() { Console.WriteLine("BeeterPhone.EstablishConnection"); } } }
class Program { static void Main(string[] args) { //SomeInternalType c=new SomeInternalType(); // Console.WriteLine(c); CompayB.BeeterPhone phone=new BeeterPhone(); phone.Dial(); Console.ReadKey(); } }
程序执行的结果为:
BeeterPhone.Dial
BeeterPhone.EstablishConnection
Phone.Dial
Phone.EstablishConnection
2.如果派生类B把虚拟方法的new关键字去掉,并把Virtual改成override话执行的结果就不一样了;
namespace CompayB { public class BeeterPhone:CompayA.Phone { public new void Dial() { Console.WriteLine("BeeterPhone.Dial"); EstablishConnection(); base.Dial(); } public override void EstablishConnection() { Console.WriteLine("BeeterPhone.EstablishConnection"); } } }
执行的结果:
BeeterPhone.Dial
BeeterPhone.EstablishConnection
Phone.Dial
BeeterPhone.EstablishConnection