测试可能性速度的程序.请注意,只有前两种方法是通用的,第三种和第四种方法仅供比较.导入 System.Reflection模块模块1公共类解析器(T 作为结构)委托函数 ParserFunction(ByVal value As String) As TPublic Shared ReadOnly Parse2 As ParserFunction = GetFunction()私有共享函数 GetFunction() 作为 ParserFunctionDim 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), _解析器函数)返回结束函数公共共享函数 Parse1(ByVal value As String) As T返回 DirectCast(Convert.ChangeType(value, GetType(T)), T)结束函数结束类子主()Dim w As New 秒表()'测试数据:Dim arrStr() As String = New String(12345678 - 1) {}Dim r 作为新随机For i As Integer = 0 To arrStr.Length - 1arrStr(i) = r.Next().ToString()下一个Dim arrInt1() As Integer = New Integer(arrStr.Length - 1) {}Dim arrInt2() As Integer = New Integer(arrStr.Length - 1) {}Console.WriteLine("1. 方法 - Convert.ChangeType:")w.Reset()w.Start()For i As Integer = 0 To arrStr.Length - 1arrInt1(i) = Parser(Of Integer).Parse1(arrStr(i))下一个w.Stop()Console.WriteLine(w.Elapsed)Console.WriteLine()Console.WriteLine("2. 方法 - 准备好的委托:")w.Reset()w.Start()For i As Integer = 0 To arrStr.Length - 1arrInt2(i) = Parser(Of Integer).Parse2(arrStr(i))下一个w.Stop()Console.WriteLine(w.Elapsed)Console.WriteLine()Console.WriteLine("3. 方法 - Integer.Parse:")w.Reset()w.Start()For i As Integer = 0 To arrStr.Length - 1arrInt2(i) = Integer.Parse(arrStr(i))下一个w.Stop()Console.WriteLine(w.Elapsed)Console.WriteLine()Console.WriteLine("4. 方法 - CType:")w.Reset()w.Start()For i As Integer = 0 To arrStr.Length - 1arrInt2(i) = CType(arrStr(i), 整数)下一个w.Stop()Console.WriteLine(w.Elapsed)Console.WriteLine()结束子终端模块如果需要,您可以更改测试元素的数量.我使用了 12345678 个随机整数.我的程序输出: 1.方法 - Convert.ChangeType:00:00:03.51760712. 方法 - 准备好的委托:00:00:02.93487923.方法 - Integer.Parse:00:00:02.84279874.方法-CType:00:00:05.0542241倍数比:3.5176071/2.9348792 = 1.20Does anyone know of a fast way in VB to go from a string to a generic type T constrained to a valuetype (Of T as Structure), when I know that T will always be some number type?This is too slow for my taste: Return DirectCast(Convert.ChangeType(myStr, GetType(T)), T)But it seems to be the only sane method of getting from a String --> T. I've tried using Reflector to see how Convert.ChangeType works, and while I can convert from the String to a given number type via a hacked-up version of that code, I have no idea how to jam that type back into T so it can be returned.I'll add that part of the speed penalty I'm seeing (in a timing loop) is because the return value is getting assigned to a Nullable(Of T) value. If I strongly-type my class for a specific number type (i.e., UInt16), then I can vastly increase the performance, but then the class would need to be duplicated for each numeric type that I use.It'd almost be nice if there was converter to/from T while working on it in a generic method/class. Maybe there is and I'm oblivious to its existence?Conclusion:Testing the three provided implementations below and my original DirectCast/ChangeType form, @peenut's approach of using a prepared delegate to fetch the Parse method from a basic type works. No error checking is done, however, so implementors need to remember to only use this with valuetypes that have a Parse method available. Or extend the below to do error checking.All runs were done on a 32bit system running Windows Server 2003 R2 with 4GB of RAM. Each "run" is 1,000,000 executions (ops) of the method to be tested, timed with StopWatch and reported back in milliseconds.Original DirectCast(Convert.ChangeType(myStr, GetType(T)), T): 1000000 ops: 597msAverage of 1000000 ops over 10 runs: 472msAverage of 1000000 ops over 10 runs: 458msAverage of 1000000 ops over 10 runs: 453msAverage of 1000000 ops over 10 runs: 466msAverage of 1000000 ops over 10 runs: 462msUsing System.Reflection and calling InvokeMethod to get at the Parse method: 1000000 ops: 12213msAverage of 1000000 ops over 10 runs: 11468msAverage of 1000000 ops over 10 runs: 11509msAverage of 1000000 ops over 10 runs: 11524msAverage of 1000000 ops over 10 runs: 11509msAverage of 1000000 ops over 10 runs: 11490msKonrad's approach to generate IL code to access the Parse method and store the call into a delegate: 1000000 ops: 352msAverage of 1000000 ops over 10 runs: 316msAverage of 1000000 ops over 10 runs: 315msAverage of 1000000 ops over 10 runs: 314msAverage of 1000000 ops over 10 runs: 314msAverage of 1000000 ops over 10 runs: 314mspeenut's approach of using a delegate to access the Parse method directly: 1000000 ops: 272msAverage of 1000000 ops over 10 runs: 272msAverage of 1000000 ops over 10 runs: 275msAverage of 1000000 ops over 10 runs: 274msAverage of 1000000 ops over 10 runs: 272msAverage of 1000000 ops over 10 runs: 273msComparatively, peenut's approach is almost 200ms faster when executed 1,000,000 times in a tight loop, so his approach wins out. Although, Konrad's wasn't far behind and is itself a fascinating study of things like ILGenerator. Props to all who contributed! 解决方案 Yes, I know about faster solution :-)Faster solution is to use prepared delegate for given (generic) Type T. If you are only interested in String->(built-in numeric type), you can simply get Parse method with one argument (String).Program to test speed of possibilities. Note that only first two methods are generic, 3rd and 4th methods are for comparison only.Imports System.ReflectionModule 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, GetType(T)), 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 SubEnd ModuleYou can change number of tested elements, if you want. I used 12345678 random integers. Program outputs for me:1. method - Convert.ChangeType:00:00:03.51760712. method - prepared delegate:00:00:02.93487923. method - Integer.Parse:00:00:02.84279874. method - CType:00:00:05.0542241Ratio of times: 3.5176071 / 2.9348792 = 1.20 这篇关于当 T 是值类型时,从 String 转换为泛型类型 T 的更快方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
09-03 05:22