自寫一個模仿Dictionary與Foreach的實(shí)現(xiàn)及心得總結(jié)
更新時(shí)間:2013年02月28日 11:41:23 作者:
利用閑暇時(shí)間自己寫一個類模仿Dictionary實(shí)現(xiàn),如果一個類進(jìn)行foreach的話,該類必須實(shí)現(xiàn)IEnumerable,集合要支持foreach方式的遍歷,必須實(shí)現(xiàn)IEnumerable接口,感興趣的你可不要錯過了哈
自己寫一個類模仿Dictionary實(shí)現(xiàn)
a、自定義字典類MyDic
using System.Collections.Generic;
namespace _10_自己寫Dictionary {
class KeyValuePair {
public KeyValuePair() {
}
public KeyValuePair(string key, string value) {
this.key = key;
this.value = value;
}
private string key;
public string Key {
get {
return key;
}
set {
key = value;
}
}
private string value;
public string Value {
get {
return this .value;
}
set {
this.value = value ;
}
}
}
class MyDic {
List<KeyValuePair > list = new List<KeyValuePair >();
public void Add(string key, string value) {
list.Add( new KeyValuePair (key, value));
}
public bool ContainsKey(string key) {
bool res = false ;
foreach(KeyValuePair item in list) {
if(item.Key == key) {
res = true;
break;
}
}
return res;
}
}
}
b、調(diào)用測試
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
namespace _10_自己寫Dictionary {
class Program {
static void Main(string[] args) {
//Dictionary方法實(shí)現(xiàn)
Dictionary<string , string> dic = new Dictionary <string, string>();
string[] filecon = File .ReadAllLines("英漢詞典TXT格式.txt", Encoding.Default);
for(int i = 0; i < filecon.Count(); i++) {
string[] arr = filecon[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if(!dic.ContainsKey(arr[0])) {
dic.Add(arr[0], arr[1]);
}
}
Stopwatch sw = new Stopwatch();
sw.Start();
dic.ContainsKey( "china");
sw.Stop();
Console.WriteLine(sw.Elapsed);//00:00:00:0000055;
//自己寫的list實(shí)現(xiàn)
MyDic mydic = new MyDic();
string[] filecon2 = File .ReadAllLines("英漢詞典TXT格式.txt", Encoding.Default);
for(int i = 0; i < filecon2.Count(); i++) {
string[] arr = filecon2[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if(!mydic.ContainsKey(arr[0])) {
mydic.Add(arr[0], arr[1]);
}
}
Stopwatch sw2 = new Stopwatch();
sw2.Start();
mydic.ContainsKey( "china");
sw2.Stop();
Console.WriteLine(sw2.Elapsed);//00:00:00:0001287;慢了多少倍!??! 因?yàn)閐ictionary比list多了字典目錄
Console.Read();
}
}
}
b中測試結(jié)果顯示自己模仿的沒有.Net FrameWork提供的快 為什么呢?
答:Dictionary中有一個存儲鍵值對的區(qū)域,這個區(qū)域的每個存儲單元有地址編號,根據(jù)hashCode算法,計(jì)算key的值的鍵值對應(yīng)該存儲的地址,將鍵值對放入指定的地址即可。查找的時(shí)候首先計(jì)算key的地址,就可以找到數(shù)據(jù)了。根據(jù)key找房間號,而不是逐個房間找。(*)或者說:當(dāng)把一個kvp,采用一個固定算法(散列算法)根據(jù)key來計(jì)算這個kvp存放的地址。取的時(shí)候也是根據(jù)要找的key可以快速算出kvp存放的地址。
面試題中經(jīng)常會問Foreach實(shí)現(xiàn)了什么接口這個問題很好回答,那我們能不能自己模仿實(shí)現(xiàn)Foreach呢?
c、Foreach內(nèi)部原理:IEnumerable接口 自己實(shí)現(xiàn)IEnumerable
using System.Collections;//引入IEnumerable所在命名空間
namespace IEnumerater {
class MyList : IEnumerable {//實(shí)現(xiàn)接口IEnumerable 它就一個IEnumerator聲明枚舉器的方法
ArrayList ary = new ArrayList();
public void Add(string name) {
ary.Add(name);
}
//自己寫索引器 形式類似屬性 作用類似枚舉 方便快捷的方式 訪問集合中的元素
public string this[ int index] {//int類型
get {
return ary[index].ToString();
} //index>ary.Count時(shí)超出索引界限
//set { }
}
public int this[ string name] {//string類型 通過name查找索引 參數(shù)類型自己決定 返回類型自己決定
get {
for(int i = 0; i < ary.Count; i++) {
if(ary[i] == name) {
return i;
}
}
return -1;
}
}
public IEnumerator GetEnumerator() {//IEnumerator F12跳轉(zhuǎn)定義這里可以發(fā)現(xiàn)foreach只允許讀取數(shù)據(jù),而不能修改數(shù)據(jù)
for(int i = 0; i < ary.Count; i++) {
yield return ary[i].ToString();// yield關(guān)鍵字 可以看到 實(shí)現(xiàn)IEnumerator(枚舉器)接口中MoveNext(指向下一條)方法 和Current(獲取當(dāng)前元素 因?yàn)橹挥術(shù)et 所以可以理解為什么foreach不能修改值的原因了) 以及Reset重置索引
}
}
}
}
d、調(diào)用自己的IEnumerable
using System;
namespace IEnumerater {
class Program {
static void Main(string[] args) {
//自己寫一個類 實(shí)現(xiàn)了IEnumerable接口的getEnumerator()方法 就可以實(shí)現(xiàn)foreach的操作
MyList mylist = new MyList();
mylist.Add( "wanghao");//調(diào)用自己的add(string)方法
mylist.Add( "nihao");
mylist.Add( "buhao");
Console.WriteLine(mylist[1]);//使用自己的索引
Console.WriteLine(mylist["nihao" ].ToString());
foreach(string item in mylist) {
Console.WriteLine(item);
//item = "hello"; 不能使用foreach改變值
}
Console.Read();
}
}
}
總結(jié):
如果一個類進(jìn)行foreach的話,該類必須實(shí)現(xiàn)IEnumerable,集合要支持foreach方式的遍歷,必須實(shí)現(xiàn)IEnumerable接口(還要以某種方式返回實(shí)現(xiàn)了IEnumerator 的對象)
a、自定義字典類MyDic
復(fù)制代碼 代碼如下:
using System.Collections.Generic;
namespace _10_自己寫Dictionary {
class KeyValuePair {
public KeyValuePair() {
}
public KeyValuePair(string key, string value) {
this.key = key;
this.value = value;
}
private string key;
public string Key {
get {
return key;
}
set {
key = value;
}
}
private string value;
public string Value {
get {
return this .value;
}
set {
this.value = value ;
}
}
}
class MyDic {
List<KeyValuePair > list = new List<KeyValuePair >();
public void Add(string key, string value) {
list.Add( new KeyValuePair (key, value));
}
public bool ContainsKey(string key) {
bool res = false ;
foreach(KeyValuePair item in list) {
if(item.Key == key) {
res = true;
break;
}
}
return res;
}
}
}
b、調(diào)用測試
復(fù)制代碼 代碼如下:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
namespace _10_自己寫Dictionary {
class Program {
static void Main(string[] args) {
//Dictionary方法實(shí)現(xiàn)
Dictionary<string , string> dic = new Dictionary <string, string>();
string[] filecon = File .ReadAllLines("英漢詞典TXT格式.txt", Encoding.Default);
for(int i = 0; i < filecon.Count(); i++) {
string[] arr = filecon[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if(!dic.ContainsKey(arr[0])) {
dic.Add(arr[0], arr[1]);
}
}
Stopwatch sw = new Stopwatch();
sw.Start();
dic.ContainsKey( "china");
sw.Stop();
Console.WriteLine(sw.Elapsed);//00:00:00:0000055;
//自己寫的list實(shí)現(xiàn)
MyDic mydic = new MyDic();
string[] filecon2 = File .ReadAllLines("英漢詞典TXT格式.txt", Encoding.Default);
for(int i = 0; i < filecon2.Count(); i++) {
string[] arr = filecon2[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if(!mydic.ContainsKey(arr[0])) {
mydic.Add(arr[0], arr[1]);
}
}
Stopwatch sw2 = new Stopwatch();
sw2.Start();
mydic.ContainsKey( "china");
sw2.Stop();
Console.WriteLine(sw2.Elapsed);//00:00:00:0001287;慢了多少倍!??! 因?yàn)閐ictionary比list多了字典目錄
Console.Read();
}
}
}
b中測試結(jié)果顯示自己模仿的沒有.Net FrameWork提供的快 為什么呢?
答:Dictionary中有一個存儲鍵值對的區(qū)域,這個區(qū)域的每個存儲單元有地址編號,根據(jù)hashCode算法,計(jì)算key的值的鍵值對應(yīng)該存儲的地址,將鍵值對放入指定的地址即可。查找的時(shí)候首先計(jì)算key的地址,就可以找到數(shù)據(jù)了。根據(jù)key找房間號,而不是逐個房間找。(*)或者說:當(dāng)把一個kvp,采用一個固定算法(散列算法)根據(jù)key來計(jì)算這個kvp存放的地址。取的時(shí)候也是根據(jù)要找的key可以快速算出kvp存放的地址。
面試題中經(jīng)常會問Foreach實(shí)現(xiàn)了什么接口這個問題很好回答,那我們能不能自己模仿實(shí)現(xiàn)Foreach呢?
c、Foreach內(nèi)部原理:IEnumerable接口 自己實(shí)現(xiàn)IEnumerable
復(fù)制代碼 代碼如下:
using System.Collections;//引入IEnumerable所在命名空間
namespace IEnumerater {
class MyList : IEnumerable {//實(shí)現(xiàn)接口IEnumerable 它就一個IEnumerator聲明枚舉器的方法
ArrayList ary = new ArrayList();
public void Add(string name) {
ary.Add(name);
}
//自己寫索引器 形式類似屬性 作用類似枚舉 方便快捷的方式 訪問集合中的元素
public string this[ int index] {//int類型
get {
return ary[index].ToString();
} //index>ary.Count時(shí)超出索引界限
//set { }
}
public int this[ string name] {//string類型 通過name查找索引 參數(shù)類型自己決定 返回類型自己決定
get {
for(int i = 0; i < ary.Count; i++) {
if(ary[i] == name) {
return i;
}
}
return -1;
}
}
public IEnumerator GetEnumerator() {//IEnumerator F12跳轉(zhuǎn)定義這里可以發(fā)現(xiàn)foreach只允許讀取數(shù)據(jù),而不能修改數(shù)據(jù)
for(int i = 0; i < ary.Count; i++) {
yield return ary[i].ToString();// yield關(guān)鍵字 可以看到 實(shí)現(xiàn)IEnumerator(枚舉器)接口中MoveNext(指向下一條)方法 和Current(獲取當(dāng)前元素 因?yàn)橹挥術(shù)et 所以可以理解為什么foreach不能修改值的原因了) 以及Reset重置索引
}
}
}
}
d、調(diào)用自己的IEnumerable
復(fù)制代碼 代碼如下:
using System;
namespace IEnumerater {
class Program {
static void Main(string[] args) {
//自己寫一個類 實(shí)現(xiàn)了IEnumerable接口的getEnumerator()方法 就可以實(shí)現(xiàn)foreach的操作
MyList mylist = new MyList();
mylist.Add( "wanghao");//調(diào)用自己的add(string)方法
mylist.Add( "nihao");
mylist.Add( "buhao");
Console.WriteLine(mylist[1]);//使用自己的索引
Console.WriteLine(mylist["nihao" ].ToString());
foreach(string item in mylist) {
Console.WriteLine(item);
//item = "hello"; 不能使用foreach改變值
}
Console.Read();
}
}
}
總結(jié):
如果一個類進(jìn)行foreach的話,該類必須實(shí)現(xiàn)IEnumerable,集合要支持foreach方式的遍歷,必須實(shí)現(xiàn)IEnumerable接口(還要以某種方式返回實(shí)現(xiàn)了IEnumerator 的對象)
相關(guān)文章
詳解ASP.NET Core 2.0 路由引擎之網(wǎng)址生成(譯)
這篇文章主要介紹了詳解ASP.NET Core 2.0 路由引擎之網(wǎng)址生成(譯),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11ASP.NET實(shí)現(xiàn)單點(diǎn)登陸(SSO)適用于多種情況
這篇文章主要介紹了ASP.NET在不同情況下實(shí)現(xiàn)單點(diǎn)登陸(SSO)的方法,在同主域但不同子域之間實(shí)現(xiàn)單點(diǎn)登陸等等2014-09-09高效的使用 Response.Redirect解決一些不必要的問題
這篇文章主要介紹了如何高效的使用 Response.Redirect解決一些不必要的問題,需要的朋友可以參考下2014-05-05asp.net頁面觸發(fā)事件panel滾動條高度不變的實(shí)現(xiàn)方法
asp.net頁面按鈕點(diǎn)擊觸發(fā)事件后panel滾動條非自動回到頂端,每次都要往下拉一下,關(guān)于這個問題的解決方法如下2014-11-11asp.net(c#)文件下載實(shí)現(xiàn)代碼
本文通過一個實(shí)例向大家介紹用C#進(jìn)行Internet通訊編程的一些基本知識。我們知道.Net類包含了請求/響應(yīng)層、應(yīng)用協(xié)議層、傳輸層等層次。2009-11-11