C# 隐式转换
我目前正在开发一个应用程序,需要从 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 转换为货币。我很困惑,因为它在任何其他情况下都工作得很好。
I'm currently working on an application where I need to load data from an SQL database and then assign the retrieved values into the properties of an object. I'm doing this by using reflection since the property names and column names are the same. However, many of the properties are using a custom struct type that is basically a currency wrapper for the decimal type. I have defined an implicit conversion in my struct:
public static implicit operator Currency(decimal d)
{
return new Currency(d);
}
This works fine when I use it in code. However, when I have this:
foreach (PropertyInfo p in props)
{
p.SetValue(this, table.Rows[0][p.Name], null);
}
It throws an ArgumentException stating that it cannot convert from System.Decimal to Currency. I'm confused since it works fine in any other circumstance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
不幸的是,这些用户定义的转换运算符不被运行时使用;它们仅由编译器在编译时使用。因此,如果您采用强类型的十进制并将其分配给强类型的货币,编译器将插入对转换运算符的调用,每个人都会很高兴。但是,当您像此处那样调用
SetValue
时,运行时希望您为其提供适当类型的值;运行时不知道此转换运算符存在,并且永远不会调用它。Unfortunately, these user-defined conversion operators are not used by the runtime; they are only used by the compiler at compile time. So if you take a strongly-typed
decimal
and assign it to a strongly-typedCurrency
, the compiler will insert a call to your conversion operator and everybody's happy. However, when you callSetValue
as you're doing here, the runtime expects you to give it a value of the appropriate type; the runtime has no idea that this conversion operator exists, and won't ever call it.我认为您需要首先将
table.Rows[0][p.Name]
中的值拆箱为decimal
。换句话说:
这是我以前见过一两次的问题,所以我实际上决定 写一篇关于它的博客文章。任何想要更多解释的人,请随时阅读。
I think you need to first unbox the value in
table.Rows[0][p.Name]
as adecimal
.In other words:
This is an issue I've seen once or twice before, so I actually decided to write a blog post about it. Anybody looking for a little more explanation, feel free to give it a read.
我假设代码中的
table
类型为DataTable
,因此第一个索引器返回DataRow
,第二个索引器返回对象。然后,PropertyInfo.SetValue 还采用一个对象作为第二个参数。此代码中没有任何地方发生强制转换,这就是不应用重载转换运算符的原因。
一般来说,它仅适用于静态类型已知的情况(暂时忘记 C# 4.0 中的
dynamic
)。装箱和拆箱时不适用。在这种情况下,DataRow
上的索引器对值进行装箱,而PropertyInfo.SetValue
尝试将其拆箱为其他类型,但失败了。I assume that
table
is of typeDataTable
in your code, so the first indexer returns aDataRow
, and the second one returns anobject
. ThenPropertyInfo.SetValue
also takes anobject
as the second argument. At no place in this code a cast happens in the code, which is why the overloaded conversion operator is not applied.Generally speaking, it is only applied when static types are known (forgetting about
dynamic
in C# 4.0 for the moment). It is not applied when boxing and unboxing things. In this case, the indexer onDataRow
boxes the value, andPropertyInfo.SetValue
tries to unbox it to a different type - and fails.虽然我没有回答您的问题,但我认为在这种情况下,使用实体框架或 NHibernate 等 ORM 框架会更合适,它将您的表映射到域对象并为您处理所有转换。使用反射之类的东西来确定要填充域对象的字段是一种缓慢的方法。
Whilst I am not answering your problem, I think in this kind of situation it would be more appropriate to use a ORM Framework like the Entity Framework or NHibernate which will map your tables into your domain objects and handle all the conversions for you. Using something like reflection to figure out what fields to fill in a domain object is a slow way to do it.