如何制作通用类型转换方法

我想做的是:

bool Convert( out Object output, Object source) { // find type of output. // convert source to that type if possible // store result in output. return success } 

可能吗?

显然,有一个强大的“if”结构可以工作,但这需要为每个可想到的数据类型编写一个if块。 即使假设我们将它限制为原语和字符串,它仍然是一大块代码。 我正在考虑一些更具反思性的东西。

旁白:在浏览api时,我遇到了Convert.IsDBNull()方法,这将为我节省很多

  if ( !databasefield.GetType().Equals( DBNull.Value ) ) 

为什么以Gd的名义在转换? 为什么不DBNull.IsDBNull()?

转换没有圣杯。 对于m种类型,您需要m *(m-1)个转换例程来覆盖所有排列。

对于基本类型,请使用Convert.ChangeType

如果一个类型可以从一个原语转换为它,它可以实现IConvertable接口并从Convert类中使用。

对于其他一切,@ Brian Rudolfs的答案是最好的。 为您需要的每个排列注册显式转换方法。

以下是我使用的示例,您可以通过注册其他类型转换器将其他复杂转换注入其中。

 public static class Converter { public static T Convert(object obj, T defaultValue) { if (obj != null) { if (obj is T) { return (T)obj; } TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); if (converter.CanConvertFrom(obj.GetType())) { return (T)converter.ConvertFrom(obj); } } return defaultValue; } 

一位开发人员写了这个函数,我们发现它非常有用。

本质上,它使用reflection来搜索两种类型之间的隐式转换(搜索“op_Implicit”以获取更多信息)。

如果不这样做,它会搜索目标类型的构造函数,该构造函数将source-type作为参数,并调用它。

如果做不到这一点,它会搜索可以将一种类型解析为另一种类型的Parse方法。 这将找到像Int32.Parse这样的东西,从String转换为Int,或IPAddress.Parse从String转换为IPAddress。

作为性能优化,一旦发现转换一次,它就会将其保存在[type,type] <==> [conversion MethodInfo]的字典中,以便后续调用不必经过广泛的reflection搜索。

这很好地处理了几乎所有的类型转换。

我多次遇到你的问题。 我总是发现构建和使用转换函数的时间抵消了它节省的时间。 最终会出现精度和舍入等问题,您仍然需要处理特殊情况。

为了检查dbnull …我使用typeof(object)是DbNull …

这是一个有趣的小练习! 我刚写了这个,所以不要挂我,如果它不起作用,但在这里我尝试转换我现在能想到的不同方法。

 public static class Converter { public static bool TryConvert(object o, out T result) { if (o == null && typeof(T).IsClass) { result = default(T); return true; } var convertible = o as IConvertible; if (convertible != null && ConvertibleHandlesDestinationType()) { result = (T)Convert.ChangeType(convertible, typeof(T)); return true; } if (o != null) { if (typeof(T).IsAssignableFrom(o.GetType())) { result = (T)o; return true; } var converter = TypeDescriptor.GetConverter(o); if (converter.CanConvertTo(typeof(T))) { result = (T)converter.ConvertTo(o, typeof(T)); return true; } } result = default(T); return false; } private static bool ConvertibleHandlesDestinationType() { return typeof(T).Equals(typeof(Boolean)) || typeof(T).Equals(typeof(Byte)) || typeof(T).Equals(typeof(char)) || typeof(T).Equals(typeof(DateTime)) || typeof(T).Equals(typeof(Decimal)) || typeof(T).Equals(typeof(Double)) || typeof(T).Equals(typeof(Int16)) || typeof(T).Equals(typeof(Int32)) || typeof(T).Equals(typeof(Int64)) || typeof(T).Equals(typeof(SByte)) || typeof(T).Equals(typeof(Single)) || typeof(T).Equals(typeof(string)) || typeof(T).Equals(typeof(UInt16)) || typeof(T).Equals(typeof(UInt32)) || typeof(T).Equals(typeof(UInt64)); } } 

由于输出参数是类型T,我们可以使用类型推断,以便调用看起来像:

 int number; if (Converter.TryConvert("123", out number)) { Debug.WriteLine(number); } 

尝试使用generics。 这样您就不必执行所有必须执行的运行时类型检查(这些都是在编译时完成的)。

即使使用Convert.IsDBNull,也有更好的方法来进行检查:

 if (!databaseField is DBNull) 

另请注意,您可以在Type上使用==,因为对于特定类型,只有一个Type实例。

你见过这个function吗?:

 Microsoft.VisualBasic.CType() 

我写了一篇关于如何在我的博客上使用DataTow管理类型转换的博客文章使用DataTables / Datarows

 /// /// Extension methods for manipulating DataRows /// public static class DataRowUserExtensions { ///  /// Determines whether [is null or empty string] [the specified data row]. ///  /// The data row. /// The key. ///  /// true if [is null or empty string] [the specified data row]; otherwise, false. ///  public static bool IsNullOrEmptyString(this DataRow dataRow, string key) { if (dataRow.Table.Columns.Contains(key)) return dataRow[key] == null || dataRow[key] == DBNull.Value || dataRow[key].ToString() == string.Empty; throw new ArgumentOutOfRangeException(key, dataRow, "does not contain column"); } ///  /// Gets the specified data row. ///  ///  /// The data row. /// The key. ///  public static T Get(this DataRow dataRow, string key) { if (dataRow.Table.Columns.Contains(key)) return dataRow.IsNullOrEmptyString(key) ? default(T) : (T) ChangeTypeTo(dataRow[key]); throw new ArgumentOutOfRangeException(key, dataRow, "does not contain column"); } ///  /// Changes the type to. ///  ///  /// The value. ///  private static object ChangeTypeTo(this object value) { if (value == null) return null; Type underlyingType = typeof (T); if (underlyingType == null) throw new ArgumentNullException("value"); if (underlyingType.IsGenericType && underlyingType.GetGenericTypeDefinition().Equals(typeof (Nullable<>))) { var converter = new NullableConverter(underlyingType); underlyingType = converter.UnderlyingType; } // Guid convert if (underlyingType == typeof (Guid)) { return new Guid(value.ToString()); } // Do conversion return underlyingType.IsAssignableFrom(value.GetType()) ? Convert.ChangeType(value, underlyingType) : Convert.ChangeType(value.ToString(), underlyingType); } }