C # conversioni implicite
-
03-10-2019 - |
Domanda
Al momento sto lavorando su una domanda in cui ho bisogno di caricare i dati da un database SQL e quindi assegnare i valori recuperati nelle proprietà di un oggetto. Sto facendo questo utilizzando riflessione dal momento che i nomi delle proprietà e delle colonne sono gli stessi. Tuttavia, molte delle proprietà utilizzano un tipo struct personalizzato che è fondamentalmente un involucro di valuta per il tipo decimale. Ho definito una conversione implicita nel mio struct:
public static implicit operator Currency(decimal d)
{
return new Currency(d);
}
Questo funziona bene quando lo uso nel 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.
Soluzione
I pensare è 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 scrivere un post su di esso . Qualcuno alla ricerca di un po 'più spiegazione, sentitevi liberi di dare una lettura.
Altri suggerimenti
Sfortunatamente, questi operatori di conversione definite dall'utente non vengono utilizzati dal runtime; sono utilizzati solo dal compilatore in fase di compilazione. Quindi, se si prende una decimal
fortemente tipizzato e assegnarlo a un Currency
fortemente tipizzato, il compilatore inserirà una chiamata al operatore di conversione e felice di tutti. Tuttavia, quando si chiama SetValue
come si sta facendo qui, il runtime si aspetta di dare un valore del tipo appropriato; il runtime non ha idea che esista questo operatore di conversione, e non potrà mai chiamarlo.
Presumo che table
è di tipo DataTable
nel codice, quindi il primo indicizzatore restituisce un DataRow
, e il secondo restituisce un object
. Poi prende PropertyInfo.SetValue
anche un object
come secondo argomento. In nessun posto in questo codice un cast accade nel codice , motivo per cui l'operatore di conversione di overload non viene applicata.
In linea generale, si applica solo quando i tipi statici sono noti (dimenticando dynamic
in C # 4.0 per il momento). Esso non si applica quando la boxe e le cose unboxing. In questo caso, l'indicizzatore su scatole DataRow
è il valore, e cerca PropertyInfo.SetValue
di unboxing ad un diverso tipo -. E non riesce
Mentre io non rispondo il problema, credo che in questo tipo di situazione, sarebbe più opportuno utilizzare un quadro ORM come Entity Framework o NHibernate che mappare le tabelle nei vostri oggetti di dominio e di gestire tutte le conversioni per voi . Usando qualcosa come riflessione per capire cosa i campi da compilare un oggetto di dominio è un modo lento per farlo.