泛型和可空类型

Phi*_*gan 8 c# generics nullable

假设我有一个方法,将int作为字符串,如果解析成功则返回int,否则返回null值.

    int? ParseValue(string intAsString)
    {
        int i;
        if (int.TryParse(intAsString, out i))
            return i;
        return null;
    }
Run Code Online (Sandbox Code Playgroud)

如何重写这个方法,使它不仅可以用于int?,还可以用long ?, decimal?和日期时间??

And*_*are 14

你应该提一下这很有趣,因为前几天我正在搞乱这样的事情:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一种类似的方法,但将其视为一种更好的TryParse返回方法Tuple<Boolean, T?>(这需要.NET 4).元组的第一个属性是一个布尔值,表示解析尝试的成功或失败,第二个属性是类型为泛型类型参数的可空值,null如果解析失败则为值,如果解析成功,则为值.

它的工作原理是使用反射Parse(String)从泛型类型参数中检索静态方法,并为传入的字符串调用该方法.我将其构建为扩展方法,允许您执行以下操作:

var intValue = "1234".TryParse<Int32>();
var doubleValue = "1234".TryParse<Double>();
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不会起作用,enums因为它们没有相同的parse方法签名,所以你不能使用这个扩展来解析一个enum但是要为枚举做一个特殊情况并不难.

这种方法的一个好处是,Parse通过反射检索方法的成本仅在第一次使用时产生,因为为所有后续使用创建了静态委托.


还有一件事 - 这种方法唯一笨拙的是,没有语言扩展或语法糖可以使这很容易使用.我希望用这个代码实现的是使用BCL中存在的标准方法的一种不那么笨重的方式TryParse.

我个人认为这种模式相当难看:

Int32 value;
if (Int32.TryParse(someString, out value))
    // do something with value
Run Code Online (Sandbox Code Playgroud)

主要是因为它需要提前声明变量并使用out参数.我上面的方法并没有那么好:

var result = someString.TryParse<Int32>();
if (result.Item1)
    // do something with result.Item2
Run Code Online (Sandbox Code Playgroud)

真正酷的是看到一个C#语言扩展,它是为了Tuple<Boolean, T?>让我们能够顺利地使用这种类型而构建的,但是我觉得我写的更多,它看起来并不可行.