这对我来说太慢了:
Return DirectCast(Convert.ChangeType(myStr,GetType(T)),T)
但它似乎是唯一一种从字符串获取的理智方法 – > T.我尝试使用Reflector来查看Convert.ChangeType是如何工作的,虽然我可以通过该代码的黑客版本从String转换为给定的数字类型,但我不知道如何将该类型转换回T所以可以退货.
我将添加我所看到的部分速度惩罚(在定时循环中)是因为返回值被分配给Nullable(Of T)值.如果我为特定的数字类型(即UInt16)强类型我的类,那么我可以大大提高性能,但是我需要为我使用的每种数字类型复制该类.
如果在通用方法/类中处理它时转换器来自T,那几乎是好的.也许存在并且我忘记了它的存在?
结论:
测试下面提供的三个实现和我原来的DirectCast / ChangeType表单,@ peenut使用预准备委托从基本类型获取Parse方法的方法有效.但是,没有进行错误检查,因此实现者需要记住只使用具有Parse方法的valuetypes.或者扩展下面的内容来进行错误检查.
所有运行都在运行Windows Server 2003 R2和4GB RAM的32位系统上完成.每次“运行”是要测试的方法的1,000,000次执行(操作),使用StopWatch计时并以毫秒为单位报告.
原始DirectCast(Convert.ChangeType(myStr,T):
1000000 ops: 597ms Average of 1000000 ops over 10 runs: 472ms Average of 1000000 ops over 10 runs: 458ms Average of 1000000 ops over 10 runs: 453ms Average of 1000000 ops over 10 runs: 466ms Average of 1000000 ops over 10 runs: 462ms
使用System.Reflection并调用InvokeMethod来获取Parse方法:
1000000 ops: 12213ms Average of 1000000 ops over 10 runs: 11468ms Average of 1000000 ops over 10 runs: 11509ms Average of 1000000 ops over 10 runs: 11524ms Average of 1000000 ops over 10 runs: 11509ms Average of 1000000 ops over 10 runs: 11490ms
Konrad生成IL代码以访问Parse方法并将调用存储到委托中的方法:
1000000 ops: 352ms Average of 1000000 ops over 10 runs: 316ms Average of 1000000 ops over 10 runs: 315ms Average of 1000000 ops over 10 runs: 314ms Average of 1000000 ops over 10 runs: 314ms Average of 1000000 ops over 10 runs: 314ms
1000000 ops: 272ms Average of 1000000 ops over 10 runs: 272ms Average of 1000000 ops over 10 runs: 275ms Average of 1000000 ops over 10 runs: 274ms Average of 1000000 ops over 10 runs: 272ms Average of 1000000 ops over 10 runs: 273ms
相比之下,peenut的方法在紧密循环中执行1,000次时快了近200ms,因此他的方法胜出.尽管如此,康拉德并不落后,而且本身就是对ILGenerator等事物的迷人研究.所有贡献者的道具!
更快的解决方案是使用为给定(通用)类型T准备的委托.如果您只对String->(内置数字类型)感兴趣,您可以简单地使用一个参数(String)获取Parse方法.
程序测试可能性的速度.请注意,前两种方法只是通用的,第三种和第四种方法仅供比较.
Imports System.Reflection Module Module1 Public Class Parser(Of T As Structure) Delegate Function ParserFunction(ByVal value As String) As T Public Shared ReadOnly Parse2 As ParserFunction = GetFunction() Private Shared Function GetFunction() As ParserFunction Dim t As Type = GetType(T) Dim m As MethodInfo = t.GetMethod("Parse",New Type() {GetType(String)}) Dim d As ParserFunction = DirectCast( _ ParserFunction.CreateDelegate(GetType(ParserFunction),m),_ ParserFunction) Return d End Function Public Shared Function Parse1(ByVal value As String) As T Return DirectCast(Convert.ChangeType(value,T) End Function End Class Sub Main() Dim w As New Stopwatch() 'test data: Dim arrStr() As String = New String(12345678 - 1) {} Dim r As New Random For i As Integer = 0 To arrStr.Length - 1 arrStr(i) = r.Next().ToString() Next Dim arrInt1() As Integer = New Integer(arrStr.Length - 1) {} Dim arrInt2() As Integer = New Integer(arrStr.Length - 1) {} Console.WriteLine("1. method - Convert.ChangeType:") w.Reset() w.Start() For i As Integer = 0 To arrStr.Length - 1 arrInt1(i) = Parser(Of Integer).Parse1(arrStr(i)) Next w.Stop() Console.WriteLine(w.Elapsed) Console.WriteLine() Console.WriteLine("2. method - prepared delegate:") w.Reset() w.Start() For i As Integer = 0 To arrStr.Length - 1 arrInt2(i) = Parser(Of Integer).Parse2(arrStr(i)) Next w.Stop() Console.WriteLine(w.Elapsed) Console.WriteLine() Console.WriteLine("3. method - Integer.Parse:") w.Reset() w.Start() For i As Integer = 0 To arrStr.Length - 1 arrInt2(i) = Integer.Parse(arrStr(i)) Next w.Stop() Console.WriteLine(w.Elapsed) Console.WriteLine() Console.WriteLine("4. method - CType:") w.Reset() w.Start() For i As Integer = 0 To arrStr.Length - 1 arrInt2(i) = CType(arrStr(i),Integer) Next w.Stop() Console.WriteLine(w.Elapsed) Console.WriteLine() End Sub End Module
如果需要,您可以更改已测试元素的数量.我使用了12345678个随机整数.我的计划输出:
1. method - Convert.ChangeType: 00:00:03.5176071 2. method - prepared delegate: 00:00:02.9348792 3. method - Integer.Parse: 00:00:02.8427987 4. method - CType: 00:00:05.0542241
次数:3.5176071 / 2.9348792 = 1.20