2010-05-05 5 views
5

Attualmente sto lavorando a un'applicazione in cui è necessario caricare i dati da un database SQL e quindi assegnare i valori recuperati alle proprietà di un oggetto. Lo sto facendo usando la reflection dato che i nomi delle proprietà e i nomi delle colonne sono gli stessi. Tuttavia, molte proprietà utilizzano un tipo di struct personalizzato che è fondamentalmente un wrapper di valuta per il tipo decimale. Ho definito una conversione implicita nella mia struct:Conversioni implicite in C#

public static implicit operator Currency(decimal d) 
{ 
    return new Currency(d); 
} 

Questo funziona bene quando lo uso in codice. Tuttavia, quando ho questo:

foreach (PropertyInfo p in props) 
{ 
    p.SetValue(this, table.Rows[0][p.Name], null); 
} 

Si genera un ArgumentException affermando che non è possibile convertire da System.Decimal alla valuta. Sono confuso dal momento che funziona bene in qualsiasi altra circostanza.

risposta

3

Io penso è necessario prima Unbox il valore in table.Rows[0][p.Name] come decimal.

In altre parole:

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

Questo è un problema che ho visto un paio di volte prima, così ho effettivamente deciso di write a blog post about it. Chiunque cerchi qualche spiegazione in più, sentiti libero di dargli una lettura.

+0

Questo ha funzionato in modo eccellente! Grazie! –

0

Sebbene io non risponda al problema, penso che in questo tipo di situazione sarebbe più appropriato utilizzare un ORM Framework come Entity Framework o NHibernate che mapperà le tabelle negli oggetti del dominio e gestirà tutte le conversioni per tu. Usare qualcosa come la riflessione per capire quali campi riempire un oggetto dominio è un modo lento per farlo.

+1

Normalmente sarei piuttosto preoccupato, ma non ha alcun impatto su quello che posso raccogliere. È un insieme relativamente piccolo di dati (56 colonne/proprietà), quindi l'overhead aggiunto non è un grosso problema. Apprezzo il suggerimento però. –

2

presumo che table è di tipo DataTable nel codice, quindi il primo indicizzatore restituisce un DataRow, e il secondo restituisce un object. Quindi il PropertyInfo.SetValue prende anche un object come secondo argomento. In nessun punto di questo codice viene eseguito un cast nel codice, motivo per cui l'operatore di conversione sovraccarico non viene applicato.

In generale, viene applicato solo quando si conoscono tipi statici (per il momento si dimentica di dynamic in C# 4.0). Non è applicato quando le cose di boxe e unboxing. In questo caso, l'indicizzatore su DataRow inserisce il valore e PropertyInfo.SetValue tenta di annullarlo in un altro tipo e non riesce.

10

Sfortunatamente, questi operatori di conversione definiti dall'utente non vengono utilizzati dal runtime; vengono utilizzati solo dal compilatore in fase di compilazione. Quindi, se prendi uno decimal fortemente digitato e lo assegni a uno Currency fortemente tipizzato, il compilatore inserirà una chiamata al tuo operatore di conversione e tutti saranno felici. Tuttavia, quando si chiama SetValue come si sta facendo qui, il runtime si aspetta di dargli un valore del tipo appropriato; il runtime non ha idea che questo operatore di conversione esista e non lo chiamerà mai.

+2

Esattamente. Le conversioni implicite sono simili ai metodi di estensione e ai parametri predefiniti, come fa il compilatore. – TomTom

+0

Ah, capisco. Apprezzo l'intuizione, dovrei essere in grado di capire un modo migliore per farlo. Grazie :) –