arrays - 如何返回在具有约束结构的泛型类中获得的字节数组作为泛型值?
问题描述
我在返回泛型时遇到了一些困难。
我有一个名为Scalar
. 它的目的是只处理数值。显然,如果不抛出运行时异常,这并不是真正可执行的。我能做的最好的就是使用Structure
约束。到目前为止,还可以接受。
在课程中,我使用一个包含表示此类泛型的字节的流。这些可以是 Byte、Int32、UInt64 等类型的序列。它们都是相同的数据类型,并且代表数字。
考虑Item
这个类中的一个函数,我在其中调用一个函数,该函数从该流中读取。结果存储在字节数组中。我知道数组的界限是因为在构建时使用 Marshal.SizeOf 评估和存储它。但是,我正在努力将此字节数组作为 datatype 返回T
。
'SizeOf:
Imports System.Runtime.InteropServices.Marshal
Public Class Scalar(Of T As Structure)
Private gtValue As T
Private giSize As Int32
Public Sub New(Value As T)
gtValue = Value
giSize = SizeOf(gtValue)
End Sub
Public Function Value() As T
Return gtValue
End Function
Public Function Item() As T
'The return value stems from a stream. It is packed into a bytes array
'of appropriate size (8 B for Int64, Double, 1 B for Byte etc.). The
'Byte array is in little endian order.
Dim abItem(0 To giSize - 1) As Byte 'Result of Stream function.
'How do I return abItem as T?
End Function
End Class
当然,我可以遍历数组并逐字节组合数字本身,然后将其作为非通用数据类型返回,例如Int64
:
Dim iElement As Int64 = 0
For i = 0 To giIndexLenBytes - 1
'Shift prior content 8 bits to the left and add new (unsigned) byte.
iElement <<= 8
iElement += abItem(i)
Next
Return iElement
我也可以使用BitConverter
and 一个Select
块来获取数字,但这会更加笨拙,最后也没有一点帮助:
Dim iElement As Int64
Select Case gtValue.GetType.ToString
Case "Byte"
iElement = abItem(0)
Case "Integer"
iElement = BitConverter.ToInt32(abItem, 0)
Case "Long"
iElement = BitConverter.ToInt64(abItem, 0)
'etc...
End Select
显然,我可以通过多种方式获得该号码。
但是,是否有可能将曾经获得的数字分配给可返回T
变量,以便泛型类对它的用户有用?
解决方案
这可能不是最有效的方法,但它是安全的,无需采取任何疯狂的措施:
Public Function CreateStructureFromByteArray(Of T As Structure)(bytes() As Byte) As T
Dim arrayPointer As IntPtr = Marshal.AllocHGlobal(bytes.Length)
Dim result As T = Nothing
Try
Marshal.Copy(bytes, 0, arrayPointer, bytes.Length)
result = Marshal.PtrToStructure(Of T)(arrayPointer)
Finally
Marshal.FreeHGlobal(arrayPointer)
End Try
Return result
End Function
请注意,这里的假设是输入字节数组包含使用与当前系统相同的字节序的数据。如果不是这种情况,您需要在调用Marshal.PtrToStructure
.
在旁注中,我曾想过尝试使用具有显式布局的结构来进行转换,如下所示:
<StructLayout(LayoutKind.Explicit)>
Structure EvilUnion(Of T As Structure)
<FieldOffset(0)> Public Byte1 As Byte
<FieldOffset(1)> Public Byte2 As Byte
<FieldOffset(2)> Public Byte3 As Byte
<FieldOffset(3)> Public Byte4 As Byte
<FieldOffset(0)> Public Struct As T
End Structure
(由于数组是引用类型,你必须为每个字节有单独的字段,就像那样,这会很痛苦。你的CreateStructureFromByteArray
函数中的代码不仅需要单独设置每个字节字段的值,而且它会还必须检查以确保泛型类型不超过 4,或者您放入的字节字段不超过多少。)
这可能是值得的,只是为了更好的性能,但不幸的是(并且不出所料)你不能StructLayoutAttribute
在通用结构上使用。那时,您将被迫为每种类型创建一个单独的显式布局结构,然后您又回到了最初的问题。
推荐阅读
- android - 如何获取初始未见活动的装备?
- python - 添加不需要数据库连接的 Django 端点
- javascript - 为什么我在使用 jquery ajax 到 php 脚本时得到 sha256.js
- javascript - 带有 forRoot 方法的惰性模块
- google-chrome-extension - 基本谷歌浏览器扩展菜鸟问题
- powershell - PowerShell:列出 CSV 文件行,其中第三列和最后一列之间的至少一个值等于“0”或“1”
- excel - 删除 CSV 中的逗号,以便在使用记事本编辑时不显示
- google-chrome - WebRTC ICE-Stun 消息完整性属性
- css - Bootstrap 4 浮动属性不适用于 SVG 元素
- python - Python numpy 数组 - 初始化第一个元素?