2011-09-30 63 views
1

我有一個用於將字符串解析爲其他類型的泛型方法(ParseTo)。這種方法收到包含方法執行委託類型參數:從接收委託類型參數的方法調用具有不同簽名的方法

public delegate bool ParseToDelegate<T>(string value, out T result); 

public static T? ParseTo<T>(this string value, 
    ParseToDelegate<T> method) where T : struct 
{ 
    T result; 
    if (String.IsNullOrWhiteSpace(value)) return null; 
    if (method(value, out result)) return result; 
    return null; 
} 

這工作得很好,因爲的TryParse的簽名是不是所有的基本類型相同。

var s = "1234,567"; 
Console.WriteLine(s.ParseTo<int>(int.TryParse)); //Error. Returns null 
Console.WriteLine(s.ParseTo<decimal>(decimal.TryParse)); //Ok 

var d = "14/05/2011 19:45"; 
Console.WriteLine(d.ParseTo<DateTime>(DateTime.TryParse)); //Ok 

var g = Guid.NewGuid().ToString(); 
Console.WriteLine(g.ParseTo<Guid>(Guid.TryParse)); //Ok 

我的問題是:現在我想擴展這個方法來支持不同的文化......但是,數字類型和日期類型具有不同的特徵:

bool TryParse(string s, NumberStyles style, IFormatProvider provider, out int result); 
bool TryParse(string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result); 

是有辦法'映射'收到的委託並調用正確的方法?事情是這樣的:

if (typeof(T) == typeof(DateTime)) 
{ 
    //Call DateTime.TryParse(string s, IFormatProvider provider, 
     //DateTimeStyles styles, out DateTime result) 
} 
else 
{ 
    //Call DateTime.TryParse(string s, 
    //NumberStyles style, IFormatProvider provider, out int result); 
} 

回答

0

,你可能會重新發明輪子 - Convert.ChangeType()確實已經幾乎正是你想要的 - 從MSDN樣本:

Temperature cool = new Temperature(5); 
Type[] targetTypes = { typeof(SByte), typeof(Int16), typeof(Int32), 
         typeof(Int64), typeof(Byte), typeof(UInt16), 
         typeof(UInt32), typeof(UInt64), typeof(Decimal), 
         typeof(Single), typeof(Double), typeof(String) }; 
CultureInfo provider = new CultureInfo("fr-FR"); 

foreach (Type targetType in targetTypes) 
{ 
    try { 
    object value = Convert.ChangeType(cool, targetType, provider); 
    Console.WriteLine("Converted {0} {1} to {2} {3}.", 
         cool.GetType().Name, cool.ToString(), 
         targetType.Name, value); 
    } 
    catch (InvalidCastException) { 
    Console.WriteLine("Unsupported {0} --> {1} conversion.", 
         cool.GetType().Name, targetType.Name); 
    }      
    catch (OverflowException) { 
    Console.WriteLine("{0} is out of range of the {1} type.", 
         cool, targetType.Name); 
    } 
} 
+0

這是一個性能問題。 –

+0

使用Convert.ChangeType或TypeConverter.ConvertFromString,您必須在運行時檢查異常。與TryParse相比,這會產生100倍的超額成本:-) –

+1

@Iluis:理解 - 所以您確實需要頻繁解析失敗? – BrokenGlass

0

這聽起來像你正在尋找類似的東西到你現在正在做的事情。在這一點上,最簡單的做法是使第二個和第三個參數成爲通用的。

public delegate bool ParseToDelegate<T,U,K>(string value, U secondOption, K thirdOption, out T result); 

public static T? ParseTo<T, U, K>(this string value, U second, K third, ParseToDelegate<T,U, K> method) where T : struct 
{ 
    T result; 
    if (String.IsNullOrWhiteSpace(value)) return null; 
    if (method(value, second, third, out result)) return result; 
    return null; 
} 

與問題,雖然是方法調用點簽名開始變得非常討厭它在很大程度上依賴於呼叫者知道代表結構,什麼通用的參數是擺在首位。

someDateString.ParseTo<DateTime, IFormatProvider, DateTimeStyles> 
      (CultureInfo.CurrentCulture.DateTimeFormat, 
      DateTimeStyles.AssumeUniversal, 
      DateTime.TryParse); 

,以減輕一點,你可能想只是包裝的具體類型的呼叫這些來電,並揭露那些作爲擴展方法代替。

public static DateTime? ParseToDateTime(this string value, IFormatProvider provider, DateTimeStyles style) 
{ 
    return ParseTo<DateTime, IFormatProvider, DateTimeStyles>(value, provider, style, DateTime.TryParse); 
} 

這將使呼叫者容易,但事物的根本膽量可能仍然是一個有點混亂,絕對應該記錄良好。

someDateString.ParseToDateTime(CultureInfo.CurrentCulture.DateTimeFormat, 
           DateTimeStyles.AssumeUniversal); 
相關問題