用Enum的时候,可能会有要遍历Enum中所有已定义值的功能。而当前各种.NET语言都没有提供对此需求的语法支持。我们只能用Enum.GetValues来实现这个任务。但是,Enum.GetValues一来是要用到运行时类型信息,让人不爽;二来得到的数组不直接是所需枚举类型的,需要转换。最好有一种强类型的语法可以帮助我们做这件事。所以,我就写了这个简单的小程序。其实内部还是得用Enum.GetValues,但是只在第一次使用时调用,后面就将这个取得的值集合保存起来,即使多次使用也不会担心性能受损。这个程序用C++/CLI BETA1写成,不适用于C++/CLI CTP或Tools Update。用C++的原因是,C#和VB.NET都对泛型约束语法做了过分的限制,让我写不了这个程序……
首先是ValueCollection类:
generic<typename T> where T : System::Enum
[DefaultMember("Item")] //让Item属性成为默认属性(C#中的索引器)
public ref class EnumValueCollection : public IEnumerable<T>
{
private:
initonly array<T>^ values;
IEnumerator<T>^ enumerator;
protected:
virtual IEnumerator<T>^ GetValuesEnumerator() = IEnumerable<T>::GetEnumerator
{
if (!enumerator)
{
enumerator = ((IEnumerable<T>^)values)->GetEnumerator();
}
return enumerator;
}
private public: // internal: in future version
EnumValueCollection(void)
{
values = (array<T>^)Enum::GetValues(typeid<T>);
}
public:
property T Item[] //参数化属性
{
T get(int index)
{
try
{
return values[index];
}
catch(Exception^ e)
{
throw gcnew ArgumentOutOfRangeException("index",
"This enum does not contain a value of this index");
}
}
}
};
接下来要有一个维护ValueCollection实例Singleton的帮助类:
generic<typename T> where T : System::Enum
public ref class EnumHelper sealed
{
private:
EnumHelper()
{
//不能创建此类的实例
}
static EnumValueCollection<T>^ valueCol;
initonly static Object^ syncRoot = gcnew Object();
public:
static property EnumValueCollection<T>^ ValueCollection
{
EnumValueCollection<T>^ get()
{
if (!valueCol)
{
try
{
Monitor::Enter(syncRoot);
if (!valueCol)
{
valueCol = gcnew EnumValueCollection<T>();
}
}
finally
{
Monitor::Exit(syncRoot);
}
}
return valueCol;
}
}
};
很简单,不用多解释了。这是用法:[Visual Basic]
For Each o As MessageBoxButtons In EnumHelper(Of MessageBoxButtons).ValueCollection
TextBox1.AppendText(o.ToString & vbCrLf)
Next
Dim x As MergeAction = EnumHelper(Of MergeAction).ValueCollection(1)
MsgBox(x.ToString)