简体   繁体   English

C#隐式转换

[英]C# implicit conversions

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. 我目前正在开发一个应用程序,我需要从SQL数据库加载数据,然后将检索到的值分配给对象的属性。 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: 我在我的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. 它抛出一个ArgumentException,声明它无法从System.Decimal转换为Currency。 I'm confused since it works fine in any other circumstance. 我很困惑,因为它在任何其他情况下都能正常工作。

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-typed Currency , the compiler will insert a call to your conversion operator and everybody's happy. 因此,如果您使用强类型decimal并将其分配给强类型Currency ,编译器将向您的转换运算符插入一个调用,并且每个人都很高兴。 However, when you call SetValue as you're doing here, the runtime expects you to give it a value of the appropriate type; 但是,当你在这里调用SetValue时,运行时期望你给它一个适当类型的值; the runtime has no idea that this conversion operator exists, and won't ever call it. 运行时不知道这个转换运算符是否存在,并且不会调用它。

I think you need to first unbox the value in table.Rows[0][p.Name] as a decimal . 你需要首先将table.Rows[0][p.Name]的值table.Rows[0][p.Name]作为decimal

In other words: 换一种说法:

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

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. 任何人都在寻找更多解释,随意给它一个阅读。

I assume that table is of type DataTable in your code, so the first indexer returns a DataRow , and the second one returns an object . 我假设该table在您的代码tableDataTable类型,因此第一个索引器返回DataRow ,第二个索引器返回一个object Then PropertyInfo.SetValue also takes an object as the second argument. 然后PropertyInfo.SetValue也将一个object作为第二个参数。 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). 一般来说,它仅在已知静态类型时才会应用(暂时忘记C#4.0中的dynamic )。 It is not applied when boxing and unboxing things. 装箱和拆箱时不适用。 In this case, the indexer on DataRow boxes the value, and PropertyInfo.SetValue tries to unbox it to a different type - and fails. 在这种情况下, DataRow上的索引器将该值设置为值,而PropertyInfo.SetValue尝试将其拆分为其他类型 - 并且失败。

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. 虽然我没有回答你的问题,但我认为在这种情况下使用像Entity Framework或NHibernate这样的ORM框架会更合适,它会将你的表映射到你的域对象并为你处理所有的转换。 Using something like reflection to figure out what fields to fill in a domain object is a slow way to do it. 使用像反射之类的东西来确定填写域对象的字段是一种缓慢的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM