当前位置:
首页 > 编程开发 > Objective-C编程 >
-
构建反转排序的泛型字典类7—实现Dictionary接口
制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
完整代码下载:http://file.ddvip.com/2008_10/1224750705_ddvip_7441.rar
7. 实现IDictionary接口
前面做了很多努力,现在终于可以实现IDictionary接口了。当然,之所以要先实现它,目的之一还是为了之前留下的一点遗憾:在foreach中使用DictionaryEntry访问集合中的元素。
需要注意,由于ReversibleSortedList类最主要的接口是泛型IDictionary接口,实现非泛型IDictionary接口主要是考虑到兼容性,试想,你的项目是用.NET 1.0实现的,但现在你需要使用.NET 2.0继续完善程序并使用到了一些.NET 2.0所独有的功能。但你并不想更改之前曾写好并稳定运行了很久的程序,此时,兼容是非常重要的。,IDictionary接口成员大部份是显式接口成员实现。这一节请对照第5节的图2观看,最好下载用图片浏览器打开,我们先改变ReversibleSortedList类的声明,加上IDictionary:
public class ReversibleSortedList<TKey, TValue> :
IDictionary, IEnumerable<KeyValuePair<TKey, TValue>>, ICollection, IEnumerable
从ICollection接口开始实现:
由于它的Count属性只是指示一个整数,可以和ICollection<KeyValuePain<TKey, TVlaue>>共用,并且前面已经实现了它,所以无需再另外实现。剩下的就只是IsSynchnonised、SyncRoot属性和CopyTo方法了,但CopyTo方法ICollection<KeyValuePain<TKey, TVlaue>>接口中也有,在MSDN中查看两个方法的定义:
ICollection中的是:
void CopyTo( Array array, int index)
而ICollection<KeyValuePain<TKey, TVlaue>>中的是
void CopyTo(T[] array, int arrayIndex)
可以看到array参数并不一样,一个是泛型,一个是数组,所以需要为这个方法实现两个版本,当然,我们先实现的是ICollection接口中的CopyTo方法:
void ICollection.CopyTo(Array array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (array.Rank != 1)
{
throw new ArgumentException(
"不支持多维数组拷贝");
}
if (array.GetLowerBound(0) != 0)
{ //检查参数数组是否下限为
throw new ArgumentException("A non-zero lower bound was provided");
}
if ((arrayIndex < 0) || (arrayIndex > array.Length))
{ //检查参数数组容量
throw new ArgumentOutOfRangeException(
"arrayIndex", "Need non negative number");
}
if ((array.Length - arrayIndex) < this.Count)
{ //检查参数数组容量
throw new ArgumentException("Array plus the offset is too small");
}
//把参数array强制转换为KeyValuePair<TKey, TValue>数组类型
KeyValuePair<TKey, TValue>[] pairArray1 =
array as KeyValuePair<TKey, TValue>[];
if (pairArray1 != null)
{ //如果转换成功,则拷贝数据
for (int num1 = 0; num1 < this.Count; num1++)
{
pairArray1[num1 + arrayIndex] =
new KeyValuePair<TKey, TValue>(this.keys[num1],
this.values[num1]);
}
}
else
{ //如果转换不成功,则把参数array强制转化为object数组
object[] objArray1 = array as object[];
if (objArray1 == null)
{
throw new ArgumentException("错误的数组类型");
}
try
{
for (int num2 = 0; num2 < this.Count; num2++)
{
objArray1[num2 + arrayIndex] =
new KeyValuePair<TKey, TValue>(this.keys[num2],
this.values[num2]);
}
}
catch (ArrayTypeMismatchException)
{
throw new ArgumentException("错误的数组类型");
}
}
}
下面实现了ICollection接口的两个私有属性:
bool ICollection.IsSynchronized
{
get
{
return false;
}
}
object ICollection.SyncRoot
{
get
{
return this;
}
}
好,现在开始正式实现IDictionary接口。首先是属性:
bool IDictionary.IsFixedSize
{
get
{
return false;
}
}
bool IDictionary.IsReadOnly
{
get
{
return false;
}
}
//item属性,本质上就是索引器
object IDictionary.this[object key]
{
get
{
if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
{
int num1 = this.IndexOfKey((TKey)key);
if (num1 >= 0)
{
return this.values[num1];
}
}
return null;
}
set
{
ReversibleSortedList<TKey, TValue>.VerifyKey(key);
ReversibleSortedList<TKey, TValue>.VerifyValueType(value);
//这里调用了IDictionary<TKey, TValue>接口的Item属性,由于
//还没有实现它,所以先把这句屏敝掉
//this[(TKey)key] = (TValue)value;
}
}
ICollection IDictionary.Keys
{
get
{
return this.GetKeyListHelper();
}
}
ICollection IDictionary.Values
{
get
{
return this.GetValueListHelper();
}
}
首先注意,全部使用了显式接口成员实现,也就是说,只能通过接口调用这些方法。另外它的Item属性调用了还未实现的IDictionary<TKey, TValue>接口的Item属性:
this[(TKey)key] = (TValue)value;
所以需要先把这句屏蔽掉,等最后再释放出来。另外调用了两个新的私有方法,也需要加进去:
private static void VerifyKey(object key)
{ //检查key类型是否兼容TKey
if (key.Equals(null))
{
throw new ArgumentNullException("key");
}
if (!(key is TKey))
{ //检查key是否和TKey兼容。注意,此时TKey已经被替换为实际类型
throw new ArgumentException(
"参数类型错误", "key");
}
}
private static void VerifyValueType(object value)
{ //检查value类型
if (!(value is TValue) && ((value != null) || typeof(TValue).IsValueType))
{
throw new ArgumentException(
"参数类型错误", "value");
}
}
VerifyValueType方法进行类型检查时有一个奇怪的判断,这一点主要是针对C#2.0的可空类型而设的。也就是说,在这里,空的值类型是合法的。关于可空类型,可以参考:
http://cgbluesky.blog.163.com/blog/static/24123558200811112926423/
下面,就剩下IDictionary接口成员方法没有实现了。其中,由于Clear()方法同时为IDictionary和ICollection <KeyValuePair<TKey, TValue>>的成员方法,但两者的返回值和参数完全相同,所以可以共用一个拷贝:
public void Clear()
{
this.version++;
Array.Clear(this.keys, 0, this._size);
Array.Clear(this.values, 0, this._size);
this._size = 0;
}
剩下的全部为显式接口成员实现:
void IDictionary.Add(object key, object value)
{ //做类型检查再添加
ReversibleSortedList<TKey, TValue>.VerifyKey(key);
ReversibleSortedList<TKey, TValue>.VerifyValueType(value);
this.Add((TKey)key, (TValue)value);
}
bool IDictionary.Contains(object key)
{
if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
{
return this.ContainsKey((TKey)key);
}
return false;
}
IDictionaryEnumerator IDictionary.GetEnumerator()
{
return new ReversibleSortedList<TKey, TValue>.Enumerator<TKey, TValue>(
this);
}
void IDictionary.Remove(object key)
{
if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
{ //这里调用了IDictionary<TKey, TValue>接口的Remove方法,由于
//还没有实现它,所以先把这句屏敝掉
// this.Remove((TKey)key);
}
}
上面代码调用了IsCompatibleKey(key)方法,需要把它加上去:
private static bool IsCompatibleKey(object key)
{ //用于检查键的类型并返回一个bool值
if (key.Equals(null))
{
throw new ArgumentNullException("key");
}
return (key is TKey);
}
其中,IDictionaryEnumerator IDictionary.GetEnumerator()方法是我们期待已久的,实现了它就可以在foreach中使用DictionaryEntry访问集合中的元素。另外Remove方法调用了IDictionary<TKey, TValue>接口的Remove方法。当然,我们还未实现它,这是第二次这样了,看样子还是首先应该实现泛型接口再实现非泛型接口。教训惨痛啊!写了这么多,懒得改了,大家知道就行了。
好!终于完成了,现在终于可以看看成果了。改变Main方法如下:
static void Main()
{
ReversibleSortedList<int, string> rs = new ReversibleSortedList<int, string>();
//添加元素
rs.Add(3, "a");
rs.Add(1, "b");
rs.Add(2, "c");
rs.Add(6, "d");
rs.Add(5, "e");
rs.Add(4, "f");
//使用DictionaryEntry打印键/值
foreach (DictionaryEntry d in (IDictionary)rs)
{
Console.WriteLine(d.Key + " " + d.Value);
}
}
ReversibleSortedList 0.6版本:实现IDictionary接口
运行结果:
1 b
2 c
3 a
4 f
5 e
6 d
很遗憾,由于IDictionary.GetEnumerator()是显式接口成员实现,只能使用接口调用。接下来,终于可以实现最重要的一个接口IDictionary<TKey, TValue>了。
void CopyTo(T[] array, int arrayIndex)
可以看到array参数并不一样,一个是泛型,一个是数组,所以需要为这个方法实现两个版本,当然,我们先实现的是ICollection接口中的CopyTo方法:
void ICollection.CopyTo(Array array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (array.Rank != 1)
{
throw new ArgumentException(
"不支持多维数组拷贝");
}
if (array.GetLowerBound(0) != 0)
{ //检查参数数组是否下限为
throw new ArgumentException("A non-zero lower bound was provided");
}
if ((arrayIndex < 0) || (arrayIndex > array.Length))
{ //检查参数数组容量
throw new ArgumentOutOfRangeException(
"arrayIndex", "Need non negative number");
}
if ((array.Length - arrayIndex) < this.Count)
{ //检查参数数组容量
throw new ArgumentException("Array plus the offset is too small");
}
//把参数array强制转换为KeyValuePair<TKey, TValue>数组类型
KeyValuePair<TKey, TValue>[] pairArray1 =
array as KeyValuePair<TKey, TValue>[];
if (pairArray1 != null)
{ //如果转换成功,则拷贝数据
for (int num1 = 0; num1 < this.Count; num1++)
{
pairArray1[num1 + arrayIndex] =
new KeyValuePair<TKey, TValue>(this.keys[num1],
this.values[num1]);
}
}
else
{ //如果转换不成功,则把参数array强制转化为object数组
object[] objArray1 = array as object[];
if (objArray1 == null)
{
throw new ArgumentException("错误的数组类型");
}
try
{
for (int num2 = 0; num2 < this.Count; num2++)
{
objArray1[num2 + arrayIndex] =
new KeyValuePair<TKey, TValue>(this.keys[num2],
this.values[num2]);
}
}
catch (ArrayTypeMismatchException)
{
throw new ArgumentException("错误的数组类型");
}
}
}
完整代码下载:http://file.ddvip.com/2008_10/1224750705_ddvip_7441.rar
7. 实现IDictionary接口
前面做了很多努力,现在终于可以实现IDictionary接口了。当然,之所以要先实现它,目的之一还是为了之前留下的一点遗憾:在foreach中使用DictionaryEntry访问集合中的元素。
需要注意,由于ReversibleSortedList类最主要的接口是泛型IDictionary接口,实现非泛型IDictionary接口主要是考虑到兼容性,试想,你的项目是用.NET 1.0实现的,但现在你需要使用.NET 2.0继续完善程序并使用到了一些.NET 2.0所独有的功能。但你并不想更改之前曾写好并稳定运行了很久的程序,此时,兼容是非常重要的。,IDictionary接口成员大部份是显式接口成员实现。这一节请对照第5节的图2观看,最好下载用图片浏览器打开,我们先改变ReversibleSortedList类的声明,加上IDictionary:
public class ReversibleSortedList<TKey, TValue> :
IDictionary, IEnumerable<KeyValuePair<TKey, TValue>>, ICollection, IEnumerable
从ICollection接口开始实现:
由于它的Count属性只是指示一个整数,可以和ICollection<KeyValuePain<TKey, TVlaue>>共用,并且前面已经实现了它,所以无需再另外实现。剩下的就只是IsSynchnonised、SyncRoot属性和CopyTo方法了,但CopyTo方法ICollection<KeyValuePain<TKey, TVlaue>>接口中也有,在MSDN中查看两个方法的定义:
ICollection中的是:
void CopyTo( Array array, int index)
而ICollection<KeyValuePain<TKey, TVlaue>>中的是
void CopyTo(T[] array, int arrayIndex)
可以看到array参数并不一样,一个是泛型,一个是数组,所以需要为这个方法实现两个版本,当然,我们先实现的是ICollection接口中的CopyTo方法:
void ICollection.CopyTo(Array array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (array.Rank != 1)
{
throw new ArgumentException(
"不支持多维数组拷贝");
}
if (array.GetLowerBound(0) != 0)
{ //检查参数数组是否下限为
throw new ArgumentException("A non-zero lower bound was provided");
}
if ((arrayIndex < 0) || (arrayIndex > array.Length))
{ //检查参数数组容量
throw new ArgumentOutOfRangeException(
"arrayIndex", "Need non negative number");
}
if ((array.Length - arrayIndex) < this.Count)
{ //检查参数数组容量
throw new ArgumentException("Array plus the offset is too small");
}
//把参数array强制转换为KeyValuePair<TKey, TValue>数组类型
KeyValuePair<TKey, TValue>[] pairArray1 =
array as KeyValuePair<TKey, TValue>[];
if (pairArray1 != null)
{ //如果转换成功,则拷贝数据
for (int num1 = 0; num1 < this.Count; num1++)
{
pairArray1[num1 + arrayIndex] =
new KeyValuePair<TKey, TValue>(this.keys[num1],
this.values[num1]);
}
}
else
{ //如果转换不成功,则把参数array强制转化为object数组
object[] objArray1 = array as object[];
if (objArray1 == null)
{
throw new ArgumentException("错误的数组类型");
}
try
{
for (int num2 = 0; num2 < this.Count; num2++)
{
objArray1[num2 + arrayIndex] =
new KeyValuePair<TKey, TValue>(this.keys[num2],
this.values[num2]);
}
}
catch (ArrayTypeMismatchException)
{
throw new ArgumentException("错误的数组类型");
}
}
}
下面实现了ICollection接口的两个私有属性:
bool ICollection.IsSynchronized
{
get
{
return false;
}
}
object ICollection.SyncRoot
{
get
{
return this;
}
}
好,现在开始正式实现IDictionary接口。首先是属性:
bool IDictionary.IsFixedSize
{
get
{
return false;
}
}
bool IDictionary.IsReadOnly
{
get
{
return false;
}
}
//item属性,本质上就是索引器
object IDictionary.this[object key]
{
get
{
if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
{
int num1 = this.IndexOfKey((TKey)key);
if (num1 >= 0)
{
return this.values[num1];
}
}
return null;
}
set
{
ReversibleSortedList<TKey, TValue>.VerifyKey(key);
ReversibleSortedList<TKey, TValue>.VerifyValueType(value);
//这里调用了IDictionary<TKey, TValue>接口的Item属性,由于
//还没有实现它,所以先把这句屏敝掉
//this[(TKey)key] = (TValue)value;
}
}
ICollection IDictionary.Keys
{
get
{
return this.GetKeyListHelper();
}
}
ICollection IDictionary.Values
{
get
{
return this.GetValueListHelper();
}
}
首先注意,全部使用了显式接口成员实现,也就是说,只能通过接口调用这些方法。另外它的Item属性调用了还未实现的IDictionary<TKey, TValue>接口的Item属性:
this[(TKey)key] = (TValue)value;
所以需要先把这句屏蔽掉,等最后再释放出来。另外调用了两个新的私有方法,也需要加进去:
private static void VerifyKey(object key)
{ //检查key类型是否兼容TKey
if (key.Equals(null))
{
throw new ArgumentNullException("key");
}
if (!(key is TKey))
{ //检查key是否和TKey兼容。注意,此时TKey已经被替换为实际类型
throw new ArgumentException(
"参数类型错误", "key");
}
}
private static void VerifyValueType(object value)
{ //检查value类型
if (!(value is TValue) && ((value != null) || typeof(TValue).IsValueType))
{
throw new ArgumentException(
"参数类型错误", "value");
}
}
VerifyValueType方法进行类型检查时有一个奇怪的判断,这一点主要是针对C#2.0的可空类型而设的。也就是说,在这里,空的值类型是合法的。关于可空类型,可以参考:
http://cgbluesky.blog.163.com/blog/static/24123558200811112926423/
下面,就剩下IDictionary接口成员方法没有实现了。其中,由于Clear()方法同时为IDictionary和ICollection <KeyValuePair<TKey, TValue>>的成员方法,但两者的返回值和参数完全相同,所以可以共用一个拷贝:
public void Clear()
{
this.version++;
Array.Clear(this.keys, 0, this._size);
Array.Clear(this.values, 0, this._size);
this._size = 0;
}
剩下的全部为显式接口成员实现:
void IDictionary.Add(object key, object value)
{ //做类型检查再添加
ReversibleSortedList<TKey, TValue>.VerifyKey(key);
ReversibleSortedList<TKey, TValue>.VerifyValueType(value);
this.Add((TKey)key, (TValue)value);
}
bool IDictionary.Contains(object key)
{
if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
{
return this.ContainsKey((TKey)key);
}
return false;
}
IDictionaryEnumerator IDictionary.GetEnumerator()
{
return new ReversibleSortedList<TKey, TValue>.Enumerator<TKey, TValue>(
this);
}
void IDictionary.Remove(object key)
{
if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
{ //这里调用了IDictionary<TKey, TValue>接口的Remove方法,由于
//还没有实现它,所以先把这句屏敝掉
// this.Remove((TKey)key);
}
}
上面代码调用了IsCompatibleKey(key)方法,需要把它加上去:
private static bool IsCompatibleKey(object key)
{ //用于检查键的类型并返回一个bool值
if (key.Equals(null))
{
throw new ArgumentNullException("key");
}
return (key is TKey);
}
其中,IDictionaryEnumerator IDictionary.GetEnumerator()方法是我们期待已久的,实现了它就可以在foreach中使用DictionaryEntry访问集合中的元素。另外Remove方法调用了IDictionary<TKey, TValue>接口的Remove方法。当然,我们还未实现它,这是第二次这样了,看样子还是首先应该实现泛型接口再实现非泛型接口。教训惨痛啊!写了这么多,懒得改了,大家知道就行了。
好!终于完成了,现在终于可以看看成果了。改变Main方法如下:
static void Main()
{
ReversibleSortedList<int, string> rs = new ReversibleSortedList<int, string>();
//添加元素
rs.Add(3, "a");
rs.Add(1, "b");
rs.Add(2, "c");
rs.Add(6, "d");
rs.Add(5, "e");
rs.Add(4, "f");
//使用DictionaryEntry打印键/值
foreach (DictionaryEntry d in (IDictionary)rs)
{
Console.WriteLine(d.Key + " " + d.Value);
}
}
ReversibleSortedList 0.6版本:实现IDictionary接口
运行结果:
1 b
2 c
3 a
4 f
5 e
6 d
很遗憾,由于IDictionary.GetEnumerator()是显式接口成员实现,只能使用接口调用。接下来,终于可以实现最重要的一个接口IDictionary<TKey, TValue>了。
void CopyTo(T[] array, int arrayIndex)
可以看到array参数并不一样,一个是泛型,一个是数组,所以需要为这个方法实现两个版本,当然,我们先实现的是ICollection接口中的CopyTo方法:
void ICollection.CopyTo(Array array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (array.Rank != 1)
{
throw new ArgumentException(
"不支持多维数组拷贝");
}
if (array.GetLowerBound(0) != 0)
{ //检查参数数组是否下限为
throw new ArgumentException("A non-zero lower bound was provided");
}
if ((arrayIndex < 0) || (arrayIndex > array.Length))
{ //检查参数数组容量
throw new ArgumentOutOfRangeException(
"arrayIndex", "Need non negative number");
}
if ((array.Length - arrayIndex) < this.Count)
{ //检查参数数组容量
throw new ArgumentException("Array plus the offset is too small");
}
//把参数array强制转换为KeyValuePair<TKey, TValue>数组类型
KeyValuePair<TKey, TValue>[] pairArray1 =
array as KeyValuePair<TKey, TValue>[];
if (pairArray1 != null)
{ //如果转换成功,则拷贝数据
for (int num1 = 0; num1 < this.Count; num1++)
{
pairArray1[num1 + arrayIndex] =
new KeyValuePair<TKey, TValue>(this.keys[num1],
this.values[num1]);
}
}
else
{ //如果转换不成功,则把参数array强制转化为object数组
object[] objArray1 = array as object[];
if (objArray1 == null)
{
throw new ArgumentException("错误的数组类型");
}
try
{
for (int num2 = 0; num2 < this.Count; num2++)
{
objArray1[num2 + arrayIndex] =
new KeyValuePair<TKey, TValue>(this.keys[num2],
this.values[num2]);
}
}
catch (ArrayTypeMismatchException)
{
throw new ArgumentException("错误的数组类型");
}
}
}
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
关于JS定时器的整理
JS中使用Promise.all控制所有的异步请求都完
js中字符串的方法
import-local执行流程与node模块路径解析流程
检测数据类型的四种方法
js中数组的方法,32种方法
前端操作方法
数据类型
window.localStorage.setItem 和 localStorage.setIte
如何完美解决前端数字计算精度丢失与数