Sto lavorando a un controllo che può assumere un numero di tipi di dati diversi (tutto ciò che implementa IComparable).Conversione di tipo generale senza rischi Eccezioni
ho bisogno di essere in grado di confrontare questi con un'altra variabile passata.
Se il tipo di dati principale è un DateTime, e io sono passata una stringa, ho bisogno di
- tentativo di convertire il Stringa a un DateTime per eseguire un confronto Data.
- se la stringa non può essere convertita in un DateTime, quindi eseguire un confronto tra stringhe.
Quindi ho bisogno di un modo generale per tentare di convertire da qualsiasi tipo a qualsiasi tipo. Abbastanza facile, .Net ci fornisce la classe TypeConverter.
Ora, il meglio che posso fare per determinare se la stringa può essere convertita in un DateTime è utilizzare le eccezioni. Se ConvertFrom genera un'eccezione, so che non posso fare la conversione e devo fare il confronto tra stringhe.
Quello che segue è il migliore che ho ottenuto:
string theString = "99/12/2009";
DateTime theDate = new DateTime (2009, 11, 1);
IComparable obj1 = theString as IComparable;
IComparable obj2 = theDate as IComparable;
try
{
TypeConverter converter = TypeDescriptor.GetConverter (obj2.GetType());
if (converter.CanConvertFrom (obj1.GetType()))
{
Console.WriteLine (obj2.CompareTo (converter.ConvertFrom (obj1)));
Console.WriteLine ("Date comparison");
}
}
catch (FormatException)
{
Console.WriteLine (obj1.ToString().CompareTo (obj2.ToString()));
Console.WriteLine ("String comparison");
}
Parte dei nostri standard a condizione del lavoro che:
eccezioni dovrebbero essere sollevate solo quando una situazione Eccezione - vale a dire. si è verificato un errore.
Ma questa non è una situazione eccezionale. Ho bisogno di un altro modo per aggirarlo.
La maggior parte dei tipi di variabile ha un metodo TryParse che restituisce un valore booleano per consentire di determinare se la conversione è riuscita o meno. Ma non esiste alcun metodo TryConvert disponibile per TypeConverter. CanConvertFrom solo dermine se è possibile convertire tra questi tipi e non considera i dati effettivi da convertire. Anche il metodo IsValid è inutile.
Qualche idea?
EDIT
non posso usare AS e IS. Non conosco i due tipi di dati al momento della compilazione. Quindi non so cosa sia come ed è !!!
EDIT
Ok inchiodato il bastardo. Non è ordinato come Marc Gravells, ma funziona (spero). Grazie per l'ispirazione Marc. Lavorerò sul riordino quando avrò il tempo, ma ho un po 'di bugfix con cui devo andare avanti.
public static class CleanConverter
{
/// <summary>
/// Stores the cache of all types that can be converted to all types.
/// </summary>
private static Dictionary<Type, Dictionary<Type, ConversionCache>> _Types = new Dictionary<Type, Dictionary<Type, ConversionCache>>();
/// <summary>
/// Try parsing.
/// </summary>
/// <param name="s"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool TryParse (IComparable s, ref IComparable value)
{
// First get the cached conversion method.
Dictionary<Type, ConversionCache> type1Cache = null;
ConversionCache type2Cache = null;
if (!_Types.ContainsKey (s.GetType()))
{
type1Cache = new Dictionary<Type, ConversionCache>();
_Types.Add (s.GetType(), type1Cache);
}
else
{
type1Cache = _Types[s.GetType()];
}
if (!type1Cache.ContainsKey (value.GetType()))
{
// We havent converted this type before, so create a new conversion
type2Cache = new ConversionCache (s.GetType(), value.GetType());
// Add to the cache
type1Cache.Add (value.GetType(), type2Cache);
}
else
{
type2Cache = type1Cache[value.GetType()];
}
// Attempt the parse
return type2Cache.TryParse (s, ref value);
}
/// <summary>
/// Stores the method to convert from Type1 to Type2
/// </summary>
internal class ConversionCache
{
internal bool TryParse (IComparable s, ref IComparable value)
{
if (this._Method != null)
{
// Invoke the cached TryParse method.
object[] parameters = new object[] { s, value };
bool result = (bool)this._Method.Invoke (null, parameters);
if (result)
value = parameters[1] as IComparable;
return result;
}
else
return false;
}
private MethodInfo _Method;
internal ConversionCache (Type type1, Type type2)
{
// Use reflection to get the TryParse method from it.
this._Method = type2.GetMethod ("TryParse", new Type[] { type1, type2.MakeByRefType() });
}
}
}
Non proprio, c'è la questione sa che cosa il tipo sta per essere convertito. Qui non lo faccio. La risposta a questa domanda non mi aiuta affatto. –
Bene. Giusto. – jason
Phew .. Pensavo che avrei chiuso la mia domanda. Ho passato ore su questo .. ;-) –