假设我有一个方法,它接受一个 int 作为字符串,如果解析成功则返回 int,否则返回 null 值。
int? ParseValue(string intAsString)
{
int i;
if (int.TryParse(intAsString, out i))
return i;
return null;
}
如何重写此方法,使其不仅适用于 int?,而且适用于 long?、decimal?和日期时间? ?
最佳答案
你应该提到它很有趣,因为前几天我正在搞乱这样的事情:
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)。元组的第一个属性是一个 bool 值,指示解析尝试的成功或失败,第二个属性是一个可以为 null 的值,类型化为泛型类型参数,即 null
。如果解析失败,则返回解析成功的值。
它通过使用反射来检索静态 Parse(String)
来工作来自泛型类型参数的方法,并为传入的字符串调用该方法。我将其构建为扩展方法,以允许您执行如下操作:
var intValue = "1234".TryParse<Int32>();
var doubleValue = "1234".TryParse<Double>();
不幸的是,这不适用于 enums
因为它们对解析方法没有相同的签名,所以你不能使用这个扩展来解析 enum
但将其破解为枚举的特例并不难。
这种方法的好处之一是检索 Parse
的成本通过反射的方法仅在第一次使用时发生,因为为所有后续使用创建了静态委托(delegate)。
还有一件事 - 这种方法唯一笨拙的地方是没有语言扩展或语法糖可以使它易于使用。我希望通过这段代码实现的是一种使用标准 TryParse
的不那么笨拙的方式。 BCL 中存在的方法。
我个人觉得这个模式相当难看:
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
真正酷的是看到一个为与 Tuple<Boolean, T?>
一起工作而构建的 C# 语言扩展。这将使我们能够顺利地使用这种类型,但我越写越觉得它似乎不太可行。
关于c# - 泛型和可空类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1878712/