C # conversions implicites
-
03-10-2019 - |
Question
Je travaille actuellement sur une application où je dois charger des données à partir d'une base de données SQL et ensuite affecter les valeurs récupérées dans les propriétés d'un objet. Je fais cela en utilisant la réflexion puisque les noms de propriétés et les noms de colonnes sont les mêmes. Cependant, la plupart des propriétés utilisent un type de struct personnalisé qui est essentiellement une enveloppe de monnaie pour le type décimal. J'ai défini une conversion implicite dans mon struct:
public static implicit operator Currency(decimal d)
{
return new Currency(d);
}
Cela fonctionne bien quand je l'utilise dans le code. Cependant, quand j'ai ceci:
foreach (PropertyInfo p in props)
{
p.SetValue(this, table.Rows[0][p.Name], null);
}
Il jette un ArgumentException indiquant qu'il ne peut pas convertir System.Decimal à la monnaie. Je suis confus car il fonctionne très bien dans toute autre circonstance.
La solution
pense vous devez d'abord Unbox la valeur table.Rows[0][p.Name]
comme decimal
.
En d'autres termes:
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);
}
}
Ceci est un problème que je l'ai vu une ou deux fois avant, donc je réellement décidé de écrire un billet de blog à ce sujet . Toute personne qui recherche un peu plus d'explications, ne hésitez pas à donner une lecture.
Autres conseils
Malheureusement, ces opérateurs de conversion définis par l'utilisateur ne sont pas utilisés par le moteur d'exécution; ils ne sont utilisés que par le compilateur au moment de la compilation. Donc, si vous prenez un decimal
et l'affecter à un Currency
fortement typé fortement typé, le compilateur insère un appel à votre opérateur de conversion et le plaisir de tout le monde. Cependant, lorsque vous appelez SetValue
que vous faites ici, le moteur d'exécution vous attend de lui donner une valeur du type approprié; le moteur d'exécution n'a aucune idée que cet opérateur de conversion existe, et ne jamais l'appeler.
Je suppose que table
est de type DataTable
dans votre code, de sorte que le premier indexeur retourne un DataRow
, et le second renvoie un object
. Puis prend PropertyInfo.SetValue
aussi un object
comme second argument. A aucun endroit dans ce code un casting qui se passe dans le code , ce qui explique pourquoi l'opérateur de conversion surchargé n'est pas appliquée.
D'une manière générale, il est appliqué uniquement lorsque les types statiques sont connus (oublier dynamic
en C # 4.0 pour le moment). Il est pas appliqué lorsque la boxe et les choses unboxing. Dans ce cas, l'indexeur sur les boîtes de DataRow
la valeur et PropertyInfo.SetValue
tente de Unbox à un type différent -. Et ne
Alors que je ne réponds pas votre problème, je pense que dans ce genre de situation, il serait plus approprié d'utiliser un cadre ORM comme Entity Framework ou NHibernate qui mapper vos tables dans vos objets de domaine et de gérer toutes les conversions pour vous . En utilisant quelque chose comme réflexion pour comprendre ce que les champs à remplir un objet de domaine est un moyen lent à le faire.