C#面向对象程序设计 $6 深入理解类
类的成员 索引函数 封装对多字段的访问 一对特殊方法 get访问器 set访问器 下标索引 读写控制 索引函数不能是静态的
索引示例 //程序清单P6_4.cs: using System; namespace P6_4 { public class IndexerSample public static void Main() Contact c1 = new Contact("赵丽"); c1["BusinessPhone"] = "010-1234567-301"; c1["BUSINESSFax"] = "010-1234567-302"; c1["homephone"] = "010-5155001"; c1.Output(); }
索引示例(续) public class Contact { //字段 private string m_name; private string m_busiPhone; private string m_busiFax; private string m_homePhone; private string m_mobilePhone; //属性 public string Name get return m_name; }
索引示例(续) //索引函数 public string this[string type] { get switch (type.ToUpper()) case "BUSINESSPHONE": return m_busiPhone; case "BUSINESSFAX": return m_busiFax; case "HOMEPHONE": return m_homePhone; case "MOBILEPHONE": return m_mobilePhone; default: return null; } set { switch (type.ToUpper()) case "BUSINESSPHONE": m_busiPhone = value; break; case "BUSINESSFAX": m_busiFax = value; case "HOMEPHONE": m_homePhone = value; case "MOBILEPHONE": m_mobilePhone = value; default: throw new ArgumentOutOfRangeException(); }
索引示例(续) //构造函数 public Contact(string name) { m_name = name; } //方法 public void Output() Console.WriteLine("联系人: {0}", m_name); Console.WriteLine("办公电话: {0}", m_busiPhone); Console.WriteLine("办公传真: {0}", m_busiFax); Console.WriteLine("住宅电话: {0}", m_homePhone); Console.WriteLine("手机: {0}", m_mobilePhone);
类的成员 事件 事件角色 类的一种特殊成员,成员类型为委托; 某事件事情发生了,通知“他人”,以便“他人”做出相应的反应。 一个是事件发送方:事件发送方是指触发事件的对象, 一个是事件接收方。事件接收方是指注册想在某种事件发生时被通知的对象。
事件举例 事件发送方:BookStore,当来了一本新书时,便触发一个事件,通知客户有新书到店。 事件接收方:客户类Customer,注册自己关心的书籍,并接收来自BookStore发送的事件。 委托(BookHandler) 实例化 事件(OnNewBook) 回调 事件处理方法 (Store_OnNewBook) 提供类 (BookStore) 订阅 包含 引发 包含 函数成员(NewBook) 客户类 (Customer)
事件示例 //程序清单P6_5.cs: using System; namespace P6_5 { public class EventSample static void Main() BookStore store = new BookStore(); Customer[] cs = new Customer[3]; cs[0] = new Customer("李明", "计算机"); cs[1] = new Customer("赵丽", "英语"); cs[2] = new Customer("Tom", "计算机"); for (int i = 0; i < 3; i++) cs[i].Register(store); store.NewBook("数据结构与算法", "计算机"); store.NewBook("国家地理杂志", "英语"); }
事件示例(续) public class Customer { private string m_name; private string m_type; public Customer(string name, string type) m_name = name; m_type = type; } public void Register(BookStore store) store.OnNewBook += new BookHandler(store_OnNewBook); //事件处理方法 void store_OnNewBook(string bookName, string bookType) if (m_type == bookType) Console.WriteLine("{0}您好:我店新到新书《{1}》", m_name, bookName); //委托定义 public delegate void BookHandler(string bookName, string bookType); public class BookStore { public void NewBook(string bookName, string bookType) OnNewBook(bookName, bookType); } //事件 public event BookHandler OnNewBook;
事件示例2 public class BookEventArgs : EventArgs { public string BookName; //程序清单P6_6.cs: using System; namespace P6_6 { public class SpecialEventSample static void Main() BookStore store = new BookStore(); Customer[] cs = new Customer[3]; cs[0] = new Customer("李明", "计算机"); cs[1] = new Customer("赵丽", "英语"); cs[2] = new Customer("Tom", "计算机"); for (int i = 0; i < 3; i++) cs[i].Register(store); store.NewBook("数据结构与算法", "计算机"); store.NewBook("国家地理杂志", "英语"); } public class BookEventArgs : EventArgs { public string BookName; public string BookType; public BookEventArgs(string name, string type) BookName = name; BookType = type; }
事件示例2(续) public class BookStore { public class Customer { private string m_name; private string m_type; public Customer(string name, string type) m_name = name; m_type = type; } public void Register(BookStore store) store.OnNewBook += new EventHandler(store_OnNewBook); //事件处理方法 void store_OnNewBook(object sender, EventArgs e) BookEventArgs be = (BookEventArgs)e; if (m_type == be.BookType) Console.WriteLine("{0}您好:我店新到新书《{1}》", m_name, be.BookName); public class BookStore { public void NewBook(string bookName, string bookType) BookEventArgs e = new BookEventArgs(bookName, bookType); OnNewBook(this, e); } //事件 public event EventHandler OnNewBook;
类的成员 操作符重载 示例P6_8 public static T operator ++(T t) public static T operator +(T t1, T t2) public static bool operator ==(T t1,T t2) public static bool operator !=(T t1,T t2) public static bool operator true (T t) public static bool operator false (T t) public static implicit operator S(T t1) - 隐式 Public static explicit operator S(T t1) - 显式 示例P6_8
Equals,ReferenceEquals,==区别 Object内置方法,它有静态方法和可重载的一个版本,用于比较两个对象的相等性。Equals它有静态方法和可重载的一个版本,事实上,这两个版本的结果完全相同,如果用户重载了Equals,调用的都是用户重载后的Equals。Equals的静态方法的好处是可以不必考虑用于比较的对象是否为null。 对于值类型,类型相同,并且数值相同,则返回true ,否则返回false。 对于引用类型,默认的行为与ReferenceEquals的行为相同,仅有两个对象指向同一个Reference的时候才返回true。可以根据需要对Equals进行重载。 ReferenceEquals方法 是Object的静态方法,用于比较两个对象的同一性 比较两个引用类型的对象,如果两个对象是同一个对象的引用,或者二者都为空引用,则返回true;否则返回 false。 如果比较的两个对象是值类型,总是返回false。 == 可以重载的二元操作符,可以用于比较两个对象是否相等。 对于值类型,判断的是两个对象的代数值是否相等。它会根据需要自动进行必要的类型转换,并根据两个对象的值是否相等返回true或者false。 对于引用类型,默认的行为与ReferenceEquals的行为相同,仅有两个对象指向同一个Reference的时候才返回true。
Equals,ReferenceEquals,==区别列表
重载==方法 obj1 == obj2 如果obj1和obj2同时为空时,返回true; 如果obj1或obj2为空时,返回false; 如果obj1和obj2两个对象的对应字段相等时,返回true,否则false。
重载GetHashCode方法 通常采取的做法是为来自相应类型的散列码应用XOR运算符,并确保XOR的操作数不相近或相等,否则结果会全是0 。 在操作数相近或相等的情况下,考虑使用移位(bitshift)和加法(add)操作。 其他备选的运算符AND和OR具有类似的限制,但这些限制会发生的更加频繁。
重载GetHashCode方法注意 第一,两个相等的对象,通过GetHashCode函数产生的结果要相等,此外两个不相等的对象,通过GetHashCode函数的返回值要不相等;否则,通过其产生HashCode而存入HashTable中的数据就无法取出来了。 第二,对于一个类型的对象来说,其GetHashCode函数的返回值要自始至终要保持一致。否则,和第一点一样。 第三,在GetHashCode函数中需要提供一个比较好的哈希函数,也就是在最小的范围内来实现数据分散,换句话说它的离散度决定HashTable存取效率。
重载Equals方法 Equals(object obj) 将obj转化为相应对象 将转化为的对象与this比较(调用==)
操作符重载示例 //程序清单P6_8.cs: using System; namespace P6_8 { public class OperatorSample static void Main() //输出前10个素数 Prime p1 = new Prime(1); for (int i1 = 0; i1 < 10; i1++) Console.WriteLine(p1++); //输出100~300之间的所有素数 for (uint i2 = 100; i2 < 300; i2++) Prime p2 = new Prime(i2); if (p2) Console.Write("{0} ", (uint)p2); }
操作符重载示例(续) public class Prime { //字段 private uint m_value; //属性 public uint Value get return m_value; } //构造函数 public Prime(uint value) { m_value = value; } //重载二元操作符 + public static uint operator +(Prime p1, Prime p2) return p1.m_value + p2.m_value; //重载二元操作符 - public static int operator -(Prime p1, Prime p2) return (int)(p1.m_value - p2.m_value);
操作符重载示例(续) //重载一元操作符 ++ public static Prime operator ++(Prime p) { for (uint i = p.m_value + 1; ; i++) if (IsPrime(i)) return new Prime(i); } //重载一元操作符 -- public static Prime operator --(Prime p) for (uint i = p.m_value - 1; i > 1; i--) return new Prime(1); //重载一元操作符 true public static bool operator true(Prime p) { return IsPrime(p.m_value); } //重载一元操作符 false public static bool operator false(Prime p) return !IsPrime(p.m_value);
操作符重载示例(续) //重载类型转换操作符(uint) public static implicit operator uint(Prime p) { return p.m_value; } //判断一个整数是否为素数 public static bool IsPrime(uint x) for (uint i = 2; i <= x / 2; i++) if (x % i == 0) return false; return true;
类的成员 this关键字 示例P6_9 表示对当前对象的引用 区分字段和外部参数 传递当前对象 public class Student { private name; public Student(string name) { this.name = name; } } 传递当前对象 示例P6_9