Estoy trabajando en un control que puede tomar varios tipos de datos diferentes (cualquier cosa que implemente IComparable).Conversión de tipo general sin riesgo Excepciones
necesito para poder compararlos con otra variable que se pasa.
Si el tipo de datos principal es un DateTime, y estoy pasa una cadena, necesito
- intento de convertir el Cadena a DateTime para realizar una comparación de fecha.
- si la Cadena no se puede convertir a un DateTime y luego hacer una comparación de Cadena.
Así que necesito una forma general de intentar convertir de cualquier tipo a cualquier tipo. Lo suficientemente fácil, .Net nos proporciona la clase TypeConverter.
Ahora, lo mejor que puedo hacer para determinar si el String se puede convertir a un DateTime es usar excepciones. Si ConvertFrom genera una excepción, sé que no puedo hacer la conversión y tengo que hacer la comparación de cadenas.
El siguiente es lo mejor que tengo:
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 de nuestros estándares en estado de trabajo que:
excepciones sólo deben plantearse cuando una situación de excepción - es decir. un error es encontrado
Pero esta no es una situación excepcional. Necesito otra forma de evitarlo.
La mayoría de los tipos de variables tienen un método TryParse que devuelve un valor booleano que le permite determinar si la conversión se realizó correctamente o no. Pero no hay un método TryConvert disponible para TypeConverter. CanConvertFrom solo afecta si es posible convertir entre estos tipos y no considera los datos reales que se convertirán. El método IsValid también es inútil.
¿Alguna idea?
EDITAR
no puedo usar AS y ES. No conozco ninguno de los tipos de datos en tiempo de compilación. ¡¡Así que no sé qué decir "As" y "Es" !!!
EDITAR
Ok clavado al bastardo. No es tan limpio como Marc Gravells, pero funciona (espero). Gracias por la inspiración Marc. Trabajaré para ponerlo en orden cuando tenga tiempo, pero tengo un montón de correcciones de errores con las que tengo que lidiar.
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() });
}
}
}
realidad, no existe la cuestión sabe lo que va a ser convertido en el tipo. Aquí no. La respuesta a esa pregunta no me ayuda en absoluto. –
Bien. Lo suficientemente justo. – jason
Phew ... Pensé que iba a cerrar mi pregunta. He pasado horas en este ... ;-) –