有趣的是你提到这个,因为我前几天也在玩类似的东西:
using System;
using System.Reflection;
static class Example
{
public static Tuple<Boolean, T?> TryParse<T>(this String candidate)
where T : struct
{
T? value = null;
Boolean success = false;
var parser = ParsingBinder<T>.GetParser();
try
{
value = parser(candidate);
success = true;
}
catch (FormatException) { }
return new Tuple<Boolean,T?>(success, value);
}
}
static class ParsingBinder<T>
{
static Func<String, T> parser;
public static Func<String, T> GetParser()
{
if (parser == null)
parser = getParser();
return parser;
}
static Func<String, T> getParser()
{
MethodInfo methodInfo
= typeof(T).GetMethod(
"Parse", new [] { typeof(String) });
if (methodInfo == null)
throw new Exception(
"Unable to retrieve a \"Parse\" method for type.");
return (Func<String, T>)Delegate
.CreateDelegate(typeof(Func<String, T>), methodInfo);
}
}
这是一种类似的方法,但可以将其视为更好的TryParse
方法,它返回一个 Tuple<Boolean, T?>
(这需要.NET 4)。元组的第一个属性是一个布尔值,表示分析尝试的成功或失败,第二个属性是可为空的值,类型为泛型类型参数,如果解析失败则为null
,如果解析成功则为值。
它通过使用反射从泛型类型参数中检索静态的Parse(String)
方法,并为传入的字符串调用该方法来工作。我将其构建为扩展方法,以允许您执行以下操作:
var intValue = "1234".TryParse<Int32>();
var doubleValue = "1234".TryParse<Double>();
很遗憾,这种方法不能用于
enums
,因为它们的解析方法签名不同,所以您无法使用此扩展来解析
enum
,但是将其修改为enums的特殊情况并不难。
这种方法的好处之一是,通过反射检索
Parse
方法的成本仅在第一次使用时发生,因为对于所有后续使用都创建了静态委托。
还有一件事——这种方法唯一笨拙的地方就是没有语言扩展或语法糖可以使其易于处理。我希望通过这段代码实现的是一种更简便的使用BCL中存在的标准
TryParse
方法的方式。
我个人认为这种模式相当丑陋:
Int32 value;
if (Int32.TryParse(someString, out value))
// do something with value
主要是因为它需要提前声明变量并使用一个
out
参数。我上面的方法并没有更好:
var result = someString.TryParse<Int32>();
if (result.Item1)
// do something with result.Item2
一个真正酷炫的想法是创建一个 C# 语言扩展,使其能够与 Tuple<Boolean, T?>
无缝协作,但我越写越觉得这个想法并不切实际。
FormatException
就是我所说的那个异常。捕获异常并不会改变抛出异常的成本。你应该查找并调用一个 TryParse 方法而不是 Parse 方法。 - Sam HarwellTryParse
方法来调用,但由于这些方法的签名因类型而异,这将使整个过程无效。再次强调,这只是一个半成品的想法,当我阅读问题时记起来的。 - Andrew HareDateTime
这样的类型),但实际上我是错误的!谢谢! - Andrew HareTryParse
方法,记得牢记这一点。 - Andrew Hare