是的,可以从字符串中解析的类型很可能具有静态 Parse 和 TryParse 重载,您可以像 Jon 建议的那样通过反射找到它们。
private static Func<string, T> GetParser<T>()
{
// The method we are searching for accepts a single string.
// You can add other types, like IFormatProvider to target specific overloads.
var signature = new[] { typeof(string) };
// Get the method with the specified name and parameters.
var method = typeof(T).GetMethod("Parse", signature);
// Initialize the parser delegate.
return s => (T)method.Invoke(null, new[] { s });
}
性能方面 - Invoke 方法将方法参数作为 object[] 接受,这是不必要的分配,如果您的参数包含值类型,则会导致装箱。它还返回一个object,导致结果数字(假设它也是一个值类型)被装箱。
为了解决这个问题,您可以构建 lambda 表达式:
private static Func<string, T> GetParser<T>()
{
// Get the method like we did before.
var signature = new[] { typeof(string) };
var method = typeof(T).GetMethod("Parse", signature);
// Build and compile a lambda expression.
var param = Expression.Parameter(typeof(string));
var call = Expression.Call(method, param);
var lambda = Expression.Lambda<Func<string, T>>(call, param);
return lambda.Compile();
}
调用已编译的 lambda 表达式几乎与调用原始解析方法本身一样快,但首先构建和编译它却不是。这就是为什么再次像 Jon 建议的那样,我们应该缓存结果委托。
我使用一个静态的通用类来缓存 ValueString 中的解析器。
private static class Parser<T>
{
public static readonly Func<string, T> Parse = InitParser();
private static Func<string, T> InitParser()
{
// Our initialization logic above.
}
}
之后你的解析方法可以这样写:
public static T Parse<T>(string s)
{
return Parser<T>.Parse(s);
}