【发布时间】:2011-01-07 20:25:36
【问题描述】:
我正在开发一个可以采用多种不同数据类型(任何实现 IComparable 的)的控件。
我需要能够将这些与传入的另一个变量进行比较。
如果主要数据类型是日期时间,并且传递给我一个字符串,我需要
- 尝试将字符串转换为 DateTime 以执行日期比较。
- 如果字符串无法转换为日期时间,则进行字符串比较。
所以我需要一种通用的方法来尝试从任何类型转换为任何类型。很简单,.Net 为我们提供了TypeConverter 类。
现在,确定字符串是否可以转换为 DateTime 的最佳方法是使用异常。如果 ConvertFrom 引发异常,我知道我无法进行转换并且必须进行字符串比较。
以下是我得到的最好的:
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" );
}
我们的部分工作标准规定:
只有在出现异常情况时才应引发异常 - 即。遇到错误。
但这不是一个例外情况。我需要另一种解决方法。
大多数变量类型都有一个TryParse 方法,该方法返回一个布尔值以允许您确定转换是否成功。但是 TypeConverter 没有可用的 TryConvert 方法。 CanConvertFrom 仅在可以在这些类型之间进行转换的情况下进行定义,并且不考虑要转换的实际数据。 IsValid 方法也没用。
有什么想法吗?
编辑
我不能使用 AS 和 IS。我在编译时不知道这两种数据类型。所以我不知道要做什么和要做什么!!!
编辑
好的,把这个混蛋钉死了。它不像 Marc Gravells 那样整洁,但它确实有效(我希望如此)。感谢马克的灵感。当我有时间时会努力整理它,但我有一些我必须继续进行的错误修复。
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 () } );
}
}
}
【问题讨论】:
-
不是真的,问题知道类型将被转换成什么。在这里我没有。这个问题的答案对我一点帮助都没有。
-
呸..我以为我要结束我的问题了。我花了几个小时在这个.. ;-)
-
当涉及到这样的标准时,您需要意识到您也在处理其他人的代码。其他人可能没有使用相同的标准。因此,虽然标准规定您不应在代码中为控制流引发异常,但如果由第 3 方编写的代码不允许您在不捕获异常的情况下轻松或优雅地编写它,那么您将不得不捕获一个例外。当然可能有一个不使用异常的解决方案,如果没有,我只想指出这一点。
-
在这种情况下使用
DateTime.TryParse有什么问题?DateTime只是一个具体的例子吗? -
@sapph 是的,它可以是任何类型。
标签: c# type-conversion