首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >VB.NET中任意类型的集合?

VB.NET中任意类型的集合?
EN

Stack Overflow用户
提问于 2010-10-21 16:18:50
回答 4查看 1.4K关注 0票数 1

所以我想知道是否有一个纯.NET的答案来表示任意数据类型的集合。我知道有旧的、后期绑定的VB6集合,但我在寻找类似泛型的东西,但要么不必在编译时指定类型,要么找到一种聪明的方法允许代码自己确定类型,然后调用某个泛型类。

为什么?我很无聊,我想尝试为NBT或NamedBinaryTag实现我自己的库会很有趣。这是流行的“我的世界”游戏中使用的存储格式。规范文档在这里:http://www.minecraft.net/docs/NBT.txt

我知道有一些现有的实现,但如果我只是为了更好地掌握文件流、字节数组、字节顺序转换和一般的.NET内容(我过去经常使用VB6/VBA,所以.NET是一个巨大的变化),那么复制这些实现就没有意义了。

让我苦恼的是TAG_Compound。根据该规范,它本质上是任何其他标记类型的对象集合,包括附加的嵌套TAG_Compounds。你可以用这种格式做一些奇怪的嵌套/递归。

我已经大概知道如何做其他类了,但是任意类型的存储使我对如何将其存储在存根类(clsTagCompound)中,以便泛型类(clsNBT(Of T))可以使用泛型函数访问有效负载产生了一个空白。

List(Of T)看起来可以工作,如果我能给它一个公共接口的话。但是由于泛型类将是使用的主要组件,它的接口也是泛型的,这只会导致讨厌的泛型链(List(Of (clsNBT(Of XXX)。

对我的想法,建议,批评?

由于此规范适用于字节流,因此以下是未压缩的NBT文件的十六进制输出(使用某个Minecraft编辑器创建)。它是一个包装在TAG_Compound中的TAG_String,虽然没有特别说明,但它通常是NBT文件中的第一个标签,它封装了所有其他标签。

0A 00 04 72 6F 6F 74 08 00 06 66 6F 6F 62 61 72 00 07 50 49 52 41 54 45 21 00

从左到右:

字节1: TagType -指定TAG_Compound。

字节2-3: TAG_Compound名称的字符串长度。

字节4-7:“根”,TAG_Compound的名称。

字节8: TagType -指定TAG_String (嵌入在TAG_Compound中)。

字节9-10: TAG_String名称的字符串长度。

字节11-16:"foobar",TAG_String的名称。

字节17-18:有效负载的长度(TAG_String,so字符串长度)。

字节19-25:“海盗!”,TAG_String的有效载荷。

字节26: TagType -指定TAG_End,标记TAG_Compound或TAG_List的结束。

同样的基本原理也适用于其他标签类型。设计非常简单,但看起来却非常强大。这可能是为什么游戏在alpha级别的代码上运行得很好的原因之一,特别是在Java中。

编辑:这里有一个指向级别规范的链接。它提供了一种更容易理解的方式来了解这些标签是如何协同工作的:

http://www.minecraftwiki.net/wiki/Alpha_Level_Format#level.dat_Format

注意:我对为游戏做任何mods不太感兴趣--我只是发现NBT格式足够整洁和简单,足以成为潜在的有用之处。已经在考虑如何扩展格式来处理标记中的无符号类型(例如,TAG_UInteger),并可能在未压缩的流前面加上一个神奇的数字(就像Linux/Unix可执行文件在前四个字节中有"ELF“一样)。这将防止其中一些工具用于打开任意/意想不到的数据格式时出现任何问题(我可能也会将这些想法传回给游戏开发人员)。

EDIT2:所以我改变了一些东西。clsNamedBinaryTag现在是一个抽象类,它实现在泛型接口中定义的泛型方法:

代码语言:javascript
复制
Friend Interface INbt(Of T)
    ...
    Function GetPayload() As T
    Function SetPayload(ByRef data As BinaryReader) As Boolean
End Interface


Friend MustInherit Class clsNamedBinaryTag(Of T)
    Implements INbt(Of T)

    ...

    Protected Friend MustOverride _
    Function GetPayload() As T _
        Implements INbt(Of T).GetPayload

    Protected Friend MustOverride _
    Function SetPayload(ByRef data As BinaryReader) As Boolean _
        Implements INbt(Of T).SetPayload
End Class

GetPayload是泛型方法,因为它将获取和返回任意类型的有效负载。非常适合像字符串之类的简单的东西。当我们遇到TAG_Compound时,情况就不那么好了。

我想做的是让所有的派生类实现INbt(Of T)。对于clsTagCompound,它的SetPayload方法将在复合的name字段被解析后开始遍历字节流。对于它遇到的每个新的TagType,理论上它会在一个temp变量Dim‘’ed to INbt(Of T)上调用DirectCast,以将其转换为定义特定TagType的类。

但这似乎并没有按计划工作。我相信我的第22个陷阱是,即使使用clsTagCompound,我仍然必须定义T,这就是我再次被卡住的地方。不知何故,我需要创建一个非泛型的接口,该接口可以应用于各种标记类型的所有类,并且仍然调用它们的GetPayload函数来返回特定于特定标记的有效负载。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-10-21 16:55:51

如果要使用可以容纳任何内容的集合类型,可以使用非泛型集合(在System.Collections namespace中)或泛型集合(Of Object)

如果想要在运行时确定对象的类型,可以使用GetType method (在确切类型上匹配)或Typeof [something] Is [sometype]结构来匹配给定接口/类的实现/继承/。More explanations on MSDN.

对于您的问题,我将编写一个通用接口ITagElement,它将由TagCompoundTagStringTagList等类实现。至于TagList类,我将使其继承System.Collections.ObjectModel namespace中的一个类。

票数 3
EN

Stack Overflow用户

发布于 2010-10-21 16:47:58

您可以将object或varientType类型用于存储任意一组对象的列表。

要在运行时找出对象类型,可以使用反射。我从未在vb.net中使用过它,但它是受支持的。

票数 0
EN

Stack Overflow用户

发布于 2010-10-21 16:53:45

我不知道您正在讨论的这种结构的细节(您到NBT.txt的链接无效...),但据我所知,您可能希望有一个clsTagCompound类作为您的基类。如果您有不同含义的TAG_Compound变体,您可以将它们声明为从clsTagCompound继承的类

然后,您可以将clsNBT声明为clsTagCompound的集合类(或者其他什么-我没有完全理解您使用clsNBT的目的)。

要处理子级别,最好在clsTagCompound上有一个子级属性

代码语言:javascript
复制
Class clsTagCompound

 Public Name As String
 Private mChildren As New List(Of clsTagCompound)
 Public ReadOnly Property Children As List(Of clsTagCompound)
  Get    
    Return mChildren 
  End Get 
 End Property
End Class

Class clsTag1
 Inherits clsTagCompound

End Class

Class clsTag2
 Inherits clsTagCompound

End Class

List(Of clsTagCompound)中的对象可以是继承clsTagCompound的任何类的对象的混合。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3985499

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档