另一套 C#,这次是泛型的
如何在 C# 中为 .NET Framework 2.0 轻松实现通用集合
引言
大家好,有兴趣的人,我希望这是一个完全功能的“Delphi”集合实现。
背景
我真的需要在 C# 中使用一些像样的集合,并且我在这里看到了两篇非常好的文章。但那些并没有让我满意,所以我编写了自己的通用集合..这次我希望这是一个明确的版本。
让我们从某个地方开始
带着我特有的傲慢,让我们在这里实现这个类:(当然,你可以根据自己的喜好命名它,但我觉得这样非常实用:)
using System;
using System.Collections;
using System.Collections.Generic;
namespace System.Collections.Generic
{
public class Set<T> : IEnumerable<T>
{
现在我们需要一些东西来存储“集合”中的值
private Dictionary<T, T> fItems =
new Dictionary<T, T>();
这很好,但要制作一个功能性的集合还有很多事情要做。例如,重写 C# 运算符以获得我们应得的所有舒适感(以及微软拒绝我们的舒适感)。
所以让我们一个接一个地来
通过这种方式,我们的“将元素包含到集合中”的运算符可能会被实现
public static Set<T> operator +(Set<T> pSource, T pElement)
{
try
{
Set<T> result = new Set<T>();
result = (Set<T>)pSource.MemberwiseClone();
result.fItems[pElement] = default(T);
return result;
}
catch (Exception E)
{
throw new Exception("Set<T> - INCLUDE" +
" operation : Error while" +
" including element into set", E);
}
}
你认为这不属于 C# 语言吗?你认为这不属于 C# 代码吗?而且它永远不会编译?好吧,我第一次也是这么认为的。
让我们回到我们的代码。现在我们可能想实现一个“排除”运算符(它很相似)
public static Set<T> operator -(Set<T> pSource, T pElement)
{
try
{
Set<T> result = new Set<T>();
result = (Set<T>)pSource.MemberwiseClone();
pSource.fItems.Remove(pElement);
return result;
}
catch (Exception E)
{
throw new Exception("Set<T> - EXCLUDE" +
" operation : Error while" +
" excluding element from set", E);
}
}
当然,如果没有“包含”运算符及其对应的“不包含”运算符,它就不能称为集合
public static Boolean operator ==(Set<T> pSource, T pElement)
{
return pSource.fItems.ContainsKey(pElement);
}
public static Boolean operator !=(Set<T> pSource, T pElement)
{
return !(pSource == pElement);
}
你可能会说这些很容易,然后我不得不告诉你..是的,它们确实是。好的。现在这里有一些真正的代码。因为我们仍然需要集合运算符。它们来了。作为第一个“并集”运算符
public static Set<T> operator +(Set<T> pSource,
Set<T> pDestiny)
{
Set<T> result = new Set<T>();
IEnumerator<T> listEnum = null;
try
{
listEnum = pSource.fItems.Keys.GetEnumerator();
listEnum.Reset();
while (listEnum.MoveNext())
{
result.fItems[listEnum.Current] = default(T);
}
}
catch (Exception E)
{
throw new Exception("Set<T> -" +
" UNION operation : Error while" +
" joining first set", E);
}
try
{
listEnum = pDestiny.fItems.Keys.GetEnumerator();
listEnum.Reset();
while (listEnum.MoveNext())
{
if (!pSource.fItems.ContainsKey(listEnum.Current))
{
result.fItems[listEnum.Current] = default(T);
}
}
}
catch (Exception E)
{
throw new Exception("Set<T> - UNION" +
" operation : Error while" +
" joining second set", E);
}
return result;
}
然后是..是的,这是一个“差集”运算符
public static Set<T> operator -(Set<T> pSource,
Set<T> pDestiny)
{
Set<T> result = new Set<T>();
IEnumerator<T> listEnum = null;
try
{
listEnum = pSource.fItems.Keys.GetEnumerator();
listEnum.Reset();
while (listEnum.MoveNext())
{
if (!pDestiny.fItems.ContainsKey(listEnum.Current))
{
result.fItems[listEnum.Current] = default(T);
}
}
}
catch (Exception E)
{
throw new Exception("Set<T> - DIFFERENCE" +
" operation : Error while forward" +
" comparing two sets for difference", E);
}
try
{
listEnum = pDestiny.fItems.Keys.GetEnumerator();
listEnum.Reset();
while (listEnum.MoveNext())
{
if (!pSource.fItems.ContainsKey(listEnum.Current))
{
result.fItems[listEnum.Current] = default(T);
}
}
}
catch (Exception E)
{
throw new Exception("Set<T> - DIFFERENCE" +
" operation : Error while backward " +
"comparing two sets for difference", E);
}
return result;
}
最后但并非最不重要的是一个“交集”运算符
public static Set<T> operator *(Set<T> pSource,
Set<T> pDestiny)
{
Set<T> result = new Set<T>();
IEnumerator<T> listEnum = null;
try
{
listEnum = pSource.fItems.Keys.GetEnumerator();
listEnum.Reset();
while (listEnum.MoveNext())
{
if (pDestiny.fItems.ContainsKey(listEnum.Current))
{
result.fItems[listEnum.Current] = default(T);
}
}
}
catch (Exception E)
{
throw new Exception("Set<T> - INTERSECTION" +
" operation : Error while comparing " +
"two sets for intersection", E);
}
return result;
}
现在来点精华
好吧,我们已经完成了基础工作,现在..既然你们都是那么好的观众,我就给你们更多:P 我发现一个非常好的事情是为集合建立索引,因为有时你只想知道集合中有什么元素,并且遍历所有元素并测试它们是否在集合中是很无聊的。你们肯定都知道我要说什么。所以现在我们准备实现一个索引器
public T this[int ItemIndex]
{
get
{
if (ItemIndex < fItems.Keys.Count)
{
IEnumerator<T> listEnum = fItems.Keys.GetEnumerator();
listEnum.Reset();
for (int a = 0; a < fItems.Keys.Count; a++)
{
if (a == ItemIndex)
{
return listEnum.Current;
}
listEnum.MoveNext();
}
}
return default(T);
}
}
另一件好事是,在使用这些类时,周围有一些智能构造函数。这些就可以了
public static Set<T> Empty()
{
return new Set<T>();
}
public static Set<T> Define(params T[] pElements)
{
Set<T> result = new Set<T>();
foreach (T element in pElements)
{
result += element;
}
return result;
}
好的,妈妈,我来做!
所以我们已经成功地添加了一些运算符和一些特殊的东西,接下来是什么..好吧,我不会骗你,这就是全部。但是我们仍然需要实现一些次要的“可能/必须”的事情。例如,实现我们一开始声明的接口
public IEnumerator<T> GetEnumerator()
{
return fItems.Keys.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return fItems.Keys.GetEnumerator();
}
当然,重写一些基本方法也是一个好习惯。因为我们不希望警告到处乱飞
public override bool Equals(object obj)
{
return (this == (Set<T>)obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public override string ToString()
{
String result = string.Empty;
IEnumerator<T> listEnum = null;
try
{
listEnum = fItems.Keys.GetEnumerator();
listEnum.Reset();
while (listEnum.MoveNext())
{
if (result == string.Empty)
{
result = listEnum.Current.ToString();
}
else
{
result += "," + listEnum.Current.ToString();
}
}
return ("{" + result + "}");
}
catch (Exception E)
{
throw new Exception("Set<T> - TOSTRING" +
" operation : Error while exporting" +
" set to string", E);
}
}
还有些东西不见了
让我们看一些例子,看看这些小野兽是如何使用的
// our testing sets make your Set<YourType>
Set<MyEnum> first =
Set<MyEnum>.Define(new MyEnum[]
{ MyEnum.One, MyEnum.Two });
Set<MyEnum> second =
Set<MyEnum>.Define(new MyEnum[]
{ MyEnum.Two, MyEnum.Three });
Set<MyEnum> result = null;
// flag of containment
Boolean contains = false;
result = first + second; // UNION
// now the result contains {One, Two, Three}
result = first - second; // DIFFERENCE
// now the result contains {One, Three}
result = first * second; // INTERSECTION
// now the result contains {Two}
contains = first == MyEnum.Three;
// contains is now FALSE because
// it doesn't contain {Three}
first += MyEnum.Three; // INCLUDE
contains = first == MyEnum.Three;
// contains is now TRUE because
// we added {Three} before
first -= MyEnum.Three;
contains = first == MyEnum.Three;
// contains is now FALSE again because
// we deleted {Three} element
今天就到这里,我希望你发现这些集合对你来说很实用,或者它们可能会启发你制作一些更好的集合。我将查看论坛 :))