5

我目前正在开发一个应用程序,我需要从 SQL 数据库加载数据,然后将检索到的值分配给对象的属性。我通过使用反射来做到这一点,因为属性名和列名是相同的。但是,许多属性都使用自定义结构类型,它基本上是小数类型的货币包装器。我在我的结构中定义了一个隐式转换:

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。我很困惑,因为它在任何其他情况下都可以正常工作。

4

4 回答 4

10

不幸的是,运行时不使用这些用户定义的转换运算符。它们仅由编译器在编译时使用。因此,如果您采用强类型decimal并将其分配给强类型Currency,编译器将插入对您的转换运算符的调用,并且每个人都很高兴。但是,当您SetValue在此处调用时,运行时希望您给它一个适当类型的值;运行时不知道此转换运算符存在,并且永远不会调用它。

于 2010-05-05T19:26:56.263 回答
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);
     }
}

这是我以前见过一两次的问题,所以我实际上决定写一篇关于它的博客文章。任何寻找更多解释的人,请随时阅读。

于 2010-05-05T19:27:40.630 回答
2

我假设这table是您的代码中的类型DataTable,因此第一个索引器返回 a DataRow,第二个索引器返回 a object。然后PropertyInfo.SetValue也将 anobject作为第二个参数。在这段代码中没有任何地方发生强制转换,这就是不应用重载转换运算符的原因。

一般来说,它仅在静态类型已知时应用(dynamic暂时忘记在 C# 4.0 中)。装箱和拆箱时不适用。在这种情况下,索引器DataRow将值装箱,并PropertyInfo.SetValue尝​​试将其拆箱为不同的类型 - 但失败了。

于 2010-05-05T19:26:07.407 回答
0

虽然我没有回答您的问题,但我认为在这种情况下,使用像实体框架或 NHibernate 这样的 ORM 框架会更合适,它将您的表映射到您的域对象并为您处理所有转换。使用反射之类的方法来确定要填充域对象的字段是一种缓慢的方法。

于 2010-05-05T19:25:32.503 回答