2014-09-04 17 views
2

我試圖構建一個更快的版本Convert.ChangeType。該類型在運行時提供。該函數用於從文本文件解析字符串等快速解析字符串到運行時提供的其他類型?

public static object ConvertTo(Type t, string s) 
{ 
    if (string.IsNullOrWhiteSpace(s) || s == null || Convert.IsDBNull(s)) return null; 
    if (t == typeof(string)) return s; 
    if (t == typeof(DateTime)) { .... /* parse and return it */ } 
    if (t == typeof(int)) { return int.Parse(s); } 
    .... 
    return Convert.ChangeType(s, t, CultureInfo.InvariantCulture); // Slowest 
} 

但是,它仍然在剖析最慢的部分。這是一種提高速度的方法嗎?

+4

嘗試使用一些鍵集合來存儲轉換的功能,如'詞典<類型,類似'HashTable'的Func >。 – 2014-09-04 19:41:12

+11

這就是爲什麼你應該首先避免這種情況。開始時,這是一個固有的昂貴的問題,將某些東西轉換爲編譯時未知的類型。你應該很少會遇到這種情況。在大多數情況下,你應該在編譯時知道你想要的類型。另外請記住,如果只有一些銀彈來解決這個問題,你不認爲這將被用作'Convert.ChangeType'的定義嗎? – Servy 2014-09-04 19:42:36

+2

@EugenePodskal只有少數幾種類型不可能產生有意義的區別。他必須有幾十種甚至數百種類型才能開始重要。 – Servy 2014-09-04 19:43:10

回答

1

將字符串轉換爲另一種類型本身就很昂貴。但是,Convert.ChangeType正在進行虛擬接口調用以及可以避免的裝箱/拆箱。

下面是它在幕後做:

public static object ChangeType(object value, Type conversionType, IFormatProvider provider) 
{ 
    if (conversionType == (Type) null) 
    throw new ArgumentNullException("conversionType"); 
    if (value == null) 
    { 
    if (conversionType.IsValueType) 
     throw new InvalidCastException(Environment.GetResourceString("InvalidCast_CannotCastNullToValueType")); 
    else 
     return (object) null; 
    } 
    else 
    { 
    IConvertible convertible = value as IConvertible; 
    if (convertible == null) 
    { 
     if (value.GetType() == conversionType) 
     return value; 
     else 
     throw new InvalidCastException(Environment.GetResourceString("InvalidCast_IConvertible")); 
    } 
    else 
    { 
     RuntimeType runtimeType = conversionType as RuntimeType; 
     if (runtimeType == Convert.ConvertTypes[3]) 
     return (object) (bool) (convertible.ToBoolean(provider) ? 1 : 0); 
     if (runtimeType == Convert.ConvertTypes[4]) 
     return (object) convertible.ToChar(provider); 
     if (runtimeType == Convert.ConvertTypes[5]) 
     return (object) convertible.ToSByte(provider); 
     if (runtimeType == Convert.ConvertTypes[6]) 
     return (object) convertible.ToByte(provider); 
     if (runtimeType == Convert.ConvertTypes[7]) 
     return (object) convertible.ToInt16(provider); 
     if (runtimeType == Convert.ConvertTypes[8]) 
     return (object) convertible.ToUInt16(provider); 
     if (runtimeType == Convert.ConvertTypes[9]) 
     return (object) convertible.ToInt32(provider); 
     if (runtimeType == Convert.ConvertTypes[10]) 
     return (object) convertible.ToUInt32(provider); 
     if (runtimeType == Convert.ConvertTypes[11]) 
     return (object) convertible.ToInt64(provider); 
     if (runtimeType == Convert.ConvertTypes[12]) 
     return (object) convertible.ToUInt64(provider); 
     if (runtimeType == Convert.ConvertTypes[13]) 
     return (object) convertible.ToSingle(provider); 
     if (runtimeType == Convert.ConvertTypes[14]) 
     return (object) convertible.ToDouble(provider); 
     if (runtimeType == Convert.ConvertTypes[15]) 
     return (object) convertible.ToDecimal(provider); 
     if (runtimeType == Convert.ConvertTypes[16]) 
     return (object) convertible.ToDateTime(provider); 
     if (runtimeType == Convert.ConvertTypes[18]) 
     return (object) convertible.ToString(provider); 
     if (runtimeType == Convert.ConvertTypes[1]) 
     return value; 
     else 
     return convertible.ToType(conversionType, provider); 
    } 
    } 
} 

下面是它的使用類型數組:

internal static readonly RuntimeType[] ConvertTypes = new RuntimeType[19] 
{ 
    (RuntimeType) typeof (Empty), 
    (RuntimeType) typeof (object), 
    (RuntimeType) typeof (DBNull), 
    (RuntimeType) typeof (bool), 
    (RuntimeType) typeof (char), 
    (RuntimeType) typeof (sbyte), 
    (RuntimeType) typeof (byte), 
    (RuntimeType) typeof (short), 
    (RuntimeType) typeof (ushort), 
    (RuntimeType) typeof (int), 
    (RuntimeType) typeof (uint), 
    (RuntimeType) typeof (long), 
    (RuntimeType) typeof (ulong), 
    (RuntimeType) typeof (float), 
    (RuntimeType) typeof (double), 
    (RuntimeType) typeof (Decimal), 
    (RuntimeType) typeof (DateTime), 
    (RuntimeType) typeof (object), 
    (RuntimeType) typeof (string) 
};