(原創) 如何建立自己的Collection? (.NET) (C#) (C++/CLI) (C/C++)
Abstract
在OO設計中,對應於Relational Database的一筆資料,我們會用一個object,如Customer,但多筆資料呢?有些人會用DataSet,有些人會用List<Customer>,這些方法都不錯,但若要設計自己的Collection:Customers type,那該怎麼做呢?
Introduction
使用DataSet(DataTable,DataReader....)或List<Customer>這些代表Collection,理論上並沒有什麼錯,事實上很多人也都這樣用,缺點就是比較沒有OO的flavor。理想上,既然有Customer class代表一筆資料,就應該有Customers class代表多筆資料,而N-Tiers間的傳輸應該是Customers collection,而非DataSet或List<Customer>。
要產生自己的Collection,有兩種方式,一個是.NET 1.0的方式,一個是.NET 2.0的方式。
.NET 1.0方式(在.NET 2.0仍然可以使用)
繼承CollectionBase,CollectionBase是一個abstract class,implement了IList ,ICollection,IEnumerable,已經為Collection做好了基礎架構,我們要做的就是overload this[]、IndexOf()、Add()、Remove()就好,其他的事情,CollectionBase已經幫我們做好了。
C#
2(C) OOMusou 2007 http://oomusou.cnblogs.com
3
4Filename : BuildOwnCollection1.cs
5Compiler : Visual Studio 2005 / C# 2.0
6Description : Demo how to build strong typed collection
7Release : 06/19/2007 1.0
8*/
9using System;
10using System.Collections;
11
12public class Member {
13 private string _name;
14
15 public Member() {}
16 public Member(string name) {
17 _name = name;
18 }
19
20 public string Name {
21 get { return _name;}
22 set { _name = value;}
23 }
24
25 public override bool Equals(object obj) {
26 Member member = (Member)obj;
27 return (_name == member.Name) ? true : false;
28 }
29
30 public override int GetHashCode() {
31 return base.GetHashCode();
32 }
33
34 public static bool operator ==(Member member1, Member member2) {
35 return member1.Equals(member2) ? true : false;
36 }
37
38 public static bool operator !=(Member member1, Member member2) {
39 return !(member1 == member2);
40 }
41}
42
43public class Members : CollectionBase {
44 public Member this[int index] {
45 get { return (Member)List[index]; }
46 set { List[index] = value; }
47 }
48
49 public int IndexOf(Member member) {
50 return this.List.IndexOf(member);
51 }
52
53 public void Add(Member member) {
54 this.List.Add(member);
55 }
56
57 public void Remove(Member member) {
58 if (this.IndexOf(member) != -1)
59 List.Remove(member);
60 }
61}
62
63public class main {
64 public static void Main() {
65 Members members = new Members();
66
67 // insert
68 members.Add(new Member("Clare"));
69 members.Add(new Member("Jessie"));
70 members.Add(new Member("Jingyi"));
71
72 // modify
73 int index = members.IndexOf(new Member("Jessie"));
74 if (index != -1) members[index] = new Member("Cerlina");
75
76 // delete
77 members.Remove(new Member("Clare"));
78
79 // search
80 index = members.IndexOf(new Member("Jingyi"));
81 if (index != -1) members.RemoveAt(index);
82
83 foreach(Member member in members) {
84 Console.WriteLine(member.Name);
85 }
86 }
87}
執行結果
在Member class中,25行到40行
Member member = (Member)obj;
return (_name == member.Name) ? true : false;
}
public override int GetHashCode() {
return base.GetHashCode();
}
public static bool operator ==(Member member1, Member member2) {
return member1.Equals(member2) ? true : false;
}
public static bool operator !=(Member member1, Member member2) {
return !(member1 == member2);
}
整體的目標是為了改寫object的比較方式,在.NET,預設是用reference比較object是否相同,但這對Collection的IndexOf(),Remove()有很大的影響,所以我override了Equals()和GetHashCode(),並對==和!=做了operator overloading。
CollectionBase原本都有實現IndexOf(),Add(),Remove(),但因只針對Object而非Member,所以針對了Member overload了IndexOf(),Add(),Remove(),另外使用了indexer是為了方便Collection的使用。
C++/CLI
2(C) OOMusou 2007 http://oomusou.cnblogs.com
3
4Filename : BuildOwnCollection1.cpp
5Compiler : Visual C++ 8.0 / C++/CLI
6Description : Demo how to build strong typed collection
7Release : 06/19/2007 1.0
8*/
9#include "stdafx.h"
10
11using namespace System;
12using namespace System::Collections;
13
14public ref class Member {
15private:
16 String^ _name;
17
18public:
19 Member() {}
20 Member(String^ name) {
21 _name = name;
22 }
23
24 property String^ Name {
25 String^ get() { return _name;}
26 void set(String^ value) { _name = value; }
27 }
28
29 virtual bool Equals(Object^ obj) override {
30 Member^ member = safe_cast<Member^>(obj);
31 return (_name == member->Name) ? true : false;
32 }
33
34 virtual int GetHashCode() override {
35 return Object::GetHashCode();
36 }
37
38 static bool operator==(Member^ member1, Member^ member2) {
39 return member1->Equals(member2) ? true : false;
40 }
41
42 static bool operator!=(Member^ member1, Member^ member2) {
43 return !(member1 == member2);
44 }
45};
46
47public ref class Members : CollectionBase {
48public:
49 property Member^ default[int] {
50 Member^ get(int index) { return safe_cast<Member^>(List[index]); }
51 void set(int index, Member^ value) { List[index] = safe_cast<Member^>(value); }
52 }
53
54 int IndexOf(Member^ member) {
55 return this->List->IndexOf(member);
56 }
57
58 void Add(Member^ member) {
59 this->List->Add(member);
60 }
61
62 void Remove(Member^ member) {
63 if (this->IndexOf(member) != -1)
64 List->Remove(member);
65 }
66};
67
68int main() {
69 Members^ members = gcnew Members;
70
71 // insert
72 members->Add(gcnew Member("Clare"));
73 members->Add(gcnew Member("Jessie"));
74 members->Add(gcnew Member("Jingyi"));
75
76 // modify
77 int index = members->IndexOf(gcnew Member("Jessie"));
78 if (index != -1)
79 members[index] = gcnew Member("Cerlina");
80
81 // delete
82 members->Remove(gcnew Member("Clare"));
83
84 // search
85 index = members->IndexOf(gcnew Member("Jingyi"));
86 if (index != -1) members->RemoveAt(index);
87
88 for each(Member^ member in members)
89 Console::WriteLine(member->Name);
90}
執行結果
.NET 2.0 (使用Collection<T>)
繼承Collection<Member>,因為是泛型,所以不用再overload IndexOf(),Add(),Remove(),也不用在定義indexer,因為泛型會直接使用Member,所以code非常精簡。
Collection<T>的架構頗複雜,implement了IEnumerable,IEnumerable<T>,ICollection,ICollection<T>,IList,IList<T>。
C#
2(C) OOMusou 2007 http://oomusou.cnblogs.com
3
4Filename : BuildOwnCollection2.cs
5Compiler : Visual Studio 2005 / C# 2.0
6Description : Demo how to build strong typed collection
7Release : 06/19/2007 1.0
8*/
9using System;
10using System.Collections.ObjectModel;
11
12public class Member {
13 private string _name;
14
15 public Member() { }
16 public Member(string name) {
17 _name = name;
18 }
19
20 public string Name {
21 get { return _name; }
22 set { _name = value; }
23 }
24
25 public override bool Equals(object obj) {
26 Member member = (Member)obj;
27 return (_name == member.Name) ? true : false;
28 }
29
30 public override int GetHashCode() {
31 return base.GetHashCode();
32 }
33
34 public static bool operator ==(Member member1, Member member2) {
35 return member1.Equals(member2) ? true : false;
36 }
37
38 public static bool operator !=(Member member1, Member member2) {
39 return !(member1 == member2);
40 }
41}
42
43public class Members : Collection<Member> {
44}
45
46public class main {
47 public static void Main() {
48 Members members = new Members();
49
50 // insert
51 members.Add(new Member("Clare"));
52 members.Add(new Member("Jessie"));
53 members.Add(new Member("Jingyi"));
54
55 // modify
56 int index = members.IndexOf(new Member("Jessie"));
57 if (index != -1) members[index] = new Member("Cerlina");
58
59 // delete
60 members.Remove(new Member("Clare"));
61
62 // search
63 index = members.IndexOf(new Member("Jingyi"));
64 if (index != -1) members.RemoveAt(index);
65
66 foreach (Member member in members) {
67 Console.WriteLine(member.Name);
68 }
69 }
70}
執行結果
35行
}
非常精簡,只需繼承Collection<Member>即可。
C++/CLI
2(C) OOMusou 2007 http://oomusou.cnblogs.com
3
4Filename : BuildOwnCollection2.cpp
5Compiler : Visual C++ 8.0 / C++/CLI
6Description : Demo how to build strong typed collection by Generics
7Release : 06/19/2007 1.0
8*/
9#include "stdafx.h"
10
11using namespace System;
12using namespace System::Collections::ObjectModel;
13
14public ref class Member {
15private:
16 String^ _name;
17
18public:
19 Member() { }
20 Member(String^ name) {
21 _name = name;
22 }
23
24public:
25 property String^ Name {
26 String^ get() { return _name; }
27 void set(String^ value) { _name = value; }
28 }
29
30 virtual bool Equals(Object^ obj) override {
31 Member^ member = safe_cast<Member^>(obj);
32 return (_name == member->Name) ? true : false;
33 }
34
35 virtual int GetHashCode() override {
36 return Object::GetHashCode();
37 }
38
39 static bool operator ==(Member^ member1, Member^ member2) {
40 return member1->Equals(member2) ? true : false;
41 }
42
43 static bool operator !=(Member^ member1, Member^ member2) {
44 return !(member1 == member2);
45 }
46};
47
48public ref class Members : Collection<Member^> {
49};
50
51int main() {
52 Members^ members = gcnew Members;
53
54 // insert
55 members->Add(gcnew Member("Clare"));
56 members->Add(gcnew Member("Jessie"));
57 members->Add(gcnew Member("Jingyi"));
58
59 // modify
60 int index = members->IndexOf(gcnew Member("Jessie"));
61 if (index != -1) members[index] = gcnew Member("Cerlina");
62
63 // delete
64 members->Remove(gcnew Member("Clare"));
65
66 // search
67 index = members->IndexOf(gcnew Member("Jingyi"));
68 if (index != -1) members->RemoveAt(index);
69
70 for each (Member^ member in members) {
71 Console::WriteLine(member->Name);
72 }
73}
執行結果
Conclusion
泛型最基本的應用,也是最原始的應用,就是在container,若用OO,只能用多型(多態)的技術,讓container放Object type,進Container須轉型成Object,出Container需再轉回各type,若用泛型,就可直接將各type放進container,不需轉型,不只速度提升,且code也非常的精簡。