我目前正在开发一个应用程序,我需要从SQL数据库加载数据,然后将检索到的值分配给对象的属性。我这样做是通过使用反射,因为属性名称和列名称是相同的。但是,许多属性都使用自定义结构类型,它基本上是十进制类型的货币包装器。我在我的struct中定义了一个隐式转换:
public static implicit operator Currency(decimal d)
{
return new Currency(d);
}
当我在代码中使用它时,这很好用。但是,当我有这个:
foreach (PropertyInfo p in props)
{
p.SetValue(this, table.Rows[0][p.Name], null);
}
它抛出一个ArgumentException,声明它无法从System.Decimal转换为Currency。我很困惑,因为它在任何其他情况下都能正常工作。
答案 0 :(得分:10)
不幸的是,运行时不使用这些用户定义的转换运算符;它们仅在编译时由编译器使用。因此,如果您使用强类型decimal
并将其分配给强类型Currency
,编译器将插入对转换运算符的调用,并且每个人都很高兴。但是,当您在此处调用SetValue
时,运行时期望您为其指定适当类型的值;运行时不知道这个转换运算符是否存在,并且不会调用它。
答案 1 :(得分:3)
我想您需要先将table.Rows[0][p.Name]
中的值取消装箱为decimal
。
换句话说:
foreach (PropertyInfo p in props)
{
if (p.PropertyType == typeof(Currency))
{
Currency c = (decimal)table.Rows[0][p.Name];
p.SetValue(this, c, null);
}
else
{
p.SetValue(this, table.Rows[0][p.Name], null);
}
}
这是我之前看过一两次的问题,所以我实际上决定write a blog post about it。任何寻求更多解释的人都可以随意阅读。
答案 2 :(得分:2)
我假设代码中table
的类型为DataTable
,因此第一个索引器返回DataRow
,第二个索引器返回object
。然后PropertyInfo.SetValue
也将object
作为第二个参数。在此代码中没有任何地方,代码在代码中发生,这就是未应用重载转换运算符的原因。
一般来说,只有在知道静态类型时才会应用它(暂时忘记C#4.0中的dynamic
)。装箱和拆箱时不适用。在这种情况下,DataRow
上的索引器会将值设为值,而PropertyInfo.SetValue
会尝试将其拆分为其他类型 - 并失败。
答案 3 :(得分:0)
虽然我没有回答您的问题,但我认为在这种情况下使用像Entity Framework或NHibernate这样的ORM框架更合适,它会将您的表映射到您的域对象并为您处理所有转换。使用像反射之类的东西来确定填写域对象的字段是一种缓慢的方法。