2011-09-30 66 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); 
相关问题