先来看这段NUnit测试代码,我们希望用反射机制在运行时访问一个对象的枚举类型的域或属性:
[TestFixture]
public class PaymentInfo
{
public enum PaymentType
{
Cash, CreditCard, Check
}
public PaymentType Type;
public void Test()
{
PaymentInfo payment = new PaymentInfo();
payment.Type = PaymentType.Cash;
System.Reflection.FieldInfo enumField = GetType().GetField("Type");
int paymentTypeInt32;
paymentTypeInt32 = (int)enumField.GetValue(payment);
Assert.AreEqual((int)PaymentType.Cash, paymentTypeInt32);
enumField.SetValue(payment, paymentTypeInt32);
Assert.AreEqual(PaymentType.Cash, payment.Type);
}
}
实际上运行测试时发现在标红的这行上抛出一个异常:“对象类型无法转换为目标类型”。究其原因,原来是因为CLR的反射机制不允许枚举类型与整数类型之间隐式转换。不过C#编译器还是允许我们通过强制类型转换的语法来进行两者间的显式转换。
在这个测试中,使之通过的办法其实非常简单:把划线部分强制转换为枚举类型即可,如:(PaymentType)paymentTypeInt32。可问题是:在运行时如何动态转换类型呢?比如说我在写ElegantDAL的时候,需要将从数据库读出的一个类型为int的数值写入到要返回的对象的一个枚举型字段中,此时我只有fieldInfo、columnValue和resultObject,然而写成fieldInfo.SetValue(resultObject, columnValue)就会出现前面提到的错误,可是我又只有一个运行时的Type信息(fieldInfo.FieldType),我又不能写成fieldInfo.SetValue(resultObject, (fieldInfo.FieldType)columnValue)……
只好将这种情况列为一个特例处理,而我们的救兵则是Enum.ToObject()方法——你知道有更好的方法解决这个问题吗?
BTW: 很多朋友写信来问偶承诺的下一篇文章什么时候才能搞定,其实我也不想拖,可最近工作确实比较紧张,而我的最佳写作时间又都在深更半夜(之前还要热身进入状态),所以迟迟不能结稿。目前其实已经写了好多(已经和第一篇长度差不多了),可是发现要写的内容还太多(也许是我写得太细了,因为我的目标不仅是讲how,更多的是what和why),所以现在决定把本篇文字再细分为两部分(上篇只讲TP/RP+MBR对象;把CBO相关的内容放到下篇再写),以便能够尽快让大家看到新的内容——嗯,争取周五release吧。至于还有朋友希望我能够深入写些关于ElegantDAL的设计与实现细节,这个留待稍后吧,正好我们将要整理的项目文档中也要有这一块内容(现在在我们这个企业级项目中用得还真挺好),到时候一起写啦(希望能够和canyue尽快完成第三版本的重写工作,目前使用的是第二版)。