C#隐式转换

5

我目前正在开发一个应用程序,需要从SQL数据库中加载数据,然后将检索到的值分配给对象的属性。由于属性名称和列名称相同,因此我使用反射来完成此操作。然而,许多属性使用自定义结构类型,该类型基本上是decimal类型的货币包装器。我在我的结构中定义了一个隐式转换:

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个回答

10

很不幸,这些用户定义的转换运算符并不会被运行时使用;它们仅在编译时由编译器使用。因此,如果你将一个强类型的decimal分配给一个强类型的 Currency,编译器将插入对你的转换运算符的调用,一切都很顺利。然而,在你像这样调用SetValue时,运行时期望你提供相应类型的值;运行时不知道这个转换运算符的存在,并且永远不会调用它。


2
没错。隐式转换类似于扩展方法和默认参数 - 这是编译器自动完成的事情。 - TomTom
啊,我明白了。感谢你提供的见解,我应该能够想出更好的方法来完成这个任务。谢谢 :) - Chris Boden

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);
     }
}

这是我之前看到过一两次的问题,所以我决定写一篇博客文章。如果有人想要更多解释,请随意阅读。


2
我假设您的代码中tableDataTable类型,所以第一个索引器返回一个DataRow,第二个索引器返回一个object。然后,PropertyInfo.SetValue也将一个object作为第二个参数。在此代码中没有发生任何强制转换在代码中,这就是为什么不会应用重载的转换运算符的原因。
一般来说,只有当静态类型已知时(暂且忘记C# 4.0中的dynamic),才会应用它。当将值装箱和拆箱时,它不会被应用。在这种情况下,DataRow的索引器会将该值装箱,而PropertyInfo.SetValue则尝试将其拆箱为另一种类型,并失败了。

0
虽然我没有回答你的问题,但在这种情况下,更适合使用ORM框架,如Entity Framework或NHibernate,它们将把您的表映射到您的域对象,并为您处理所有转换。使用反射来确定要填充域对象中的哪些字段是一种缓慢的方法。

1
通常我会很担心,但据我所知,它并没有对其产生影响。这是一个相对较小的数据集(56个列/属性),因此额外的开销不是一个大问题。但我还是很感谢您的建议。 - Chris Boden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接