C#隐式转换

时间:2010-05-05 19:22:15

标签: c# implicit-conversion

我目前正在开发一个应用程序,我需要从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。我很困惑,因为它在任何其他情况下都能正常工作。

4 个答案:

答案 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框架更合适,它会将您的表映射到您的域对象并为您处理所有转换。使用像反射之类的东西来确定填写域对象的字段是一种缓慢的方法。