(原創) 如何建立自己的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#

 1/* 
 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}


執行結果

Cerlina


在Member class中,25行到40行

public override bool Equals(object obj) {
  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

 1/* 
 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}


執行結果

Cerlina


.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#

 1/* 
 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}


執行結果

Cerlina


35行

public class Members : Collection<Member> {
}


非常精簡,只需繼承Collection<Member>即可。

C++/CLI

 1/* 
 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}


執行結果

Cerlina


Conclusion
泛型最基本的應用,也是最原始的應用,就是在container,若用OO,只能用多型(多態)的技術,讓container放Object type,進Container須轉型成Object,出Container需再轉回各type,若用泛型,就可直接將各type放進container,不需轉型,不只速度提升,且code也非常的精簡。

posted on 2007-06-19 12:51  真 OO无双  阅读(8101)  评论(13编辑  收藏  举报

导航