我想做的是:
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 ) )
为什么G-d的名字是转换?为什么不DBNull.IsDBNull()?
答案 0 :(得分:3)
以下是我使用的示例,您可以通过注册其他类型的转换器将其他复杂的转换注入其中。
public static class Converter
{
public static T Convert<T>(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;
}
答案 1 :(得分:3)
一位开发者正好写了这个函数,我们发现它非常有用。
基本上,它使用反射来搜索两种类型之间的隐式转换(搜索“op_Implicit”以获取更多信息)。
如果失败,它会搜索目标类型的构造函数,该构造函数将source-type作为参数,然后调用它。
如果失败,它会搜索可以将一种类型解析为另一种类型的Parse方法。这将找到像Int32.Parse这样的东西,从String转换为Int,或IPAddress.Parse从String转换为IPAddress。
作为性能优化,一旦找到转换一次,它就会将其保存在[type,type]&lt; ==&gt;的字典中。 [转换MethodInfo],以便后续调用不必进行广泛的反射搜索。
这几乎可以很好地处理所有类型转换。
答案 2 :(得分:2)
我多次遇到你的问题。我总是发现构建和使用转换函数的时间抵消了它节省的时间。最终会出现精度和舍入等问题,您仍然需要处理特殊情况。
用于检查dbnull ...我使用typeof(object)是DbNull ...
答案 3 :(得分:2)
这是一个有趣的小练习!我刚刚写了这个,所以不要挂我,如果它不起作用,但在这里我尝试转换我现在能想到的不同方法。
public static class Converter
{
public static bool TryConvert<T>(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<T>())
{
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<T>()
{
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);
}
答案 4 :(得分:1)
即使使用Convert.IsDBNull,也可以采用更好的方式进行检查:
if (!databaseField is DBNull)
另请注意,您可以在Type上使用==,因为特定类型只有一个Type实例。
答案 5 :(得分:0)
尝试使用泛型。这样您就不必进行所有必须执行的运行时类型检查(这些都是在编译时完成的。)
答案 6 :(得分:0)
你见过这个功能吗?:
Microsoft.VisualBasic.CType()
答案 7 :(得分:0)
我写了一篇关于如何在我的博客上管理DataRow类型转换的博文Working with DataTables/Datarows
///<summary>
/// Extension methods for manipulating DataRows
///</summary>
public static class DataRowUserExtensions
{
/// <summary>
/// Determines whether [is null or empty string] [the specified data row].
/// </summary>
/// <param name="dataRow">The data row.</param>
/// <param name="key">The key.</param>
/// <returns>
/// <c>true</c> if [is null or empty string] [the specified data row]; otherwise, <c>false</c>.
/// </returns>
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");
}
/// <summary>
/// Gets the specified data row.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dataRow">The data row.</param>
/// <param name="key">The key.</param>
/// <returns></returns>
public static T Get<T>(this DataRow dataRow, string key)
{
if (dataRow.Table.Columns.Contains(key))
return dataRow.IsNullOrEmptyString(key) ? default(T) : (T) ChangeTypeTo<T>(dataRow[key]);
throw new ArgumentOutOfRangeException(key, dataRow, "does not contain column");
}
/// <summary>
/// Changes the type to.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value">The value.</param>
/// <returns></returns>
private static object ChangeTypeTo<T>(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);
}
}
答案 8 :(得分:0)
没有转变的圣杯。对于m种类型,您需要m *(m-1)个转换例程来覆盖所有排列。
对于基本类型,请使用Convert.ChangeType
如果一个类型可以从一个原语转换为它,它可以实现IConvertable接口并从Convert类中使用。
对于其他一切,@ Brian Rudolfs的答案是最好的。为您需要的每个排列注册显式转换方法。