我有一个2D阵列,我想填充到另一个。我在列表,字典和简单数组之间有点混淆,所以我认为我有两种不同的类型或数组。编辑过的代码有一些尝试和产生的错误:
Dim _inifile As String = "C:\Users\Steve\Scripts\Projects\IniRecEdit\Tests\insrow.ini"
Public IniLines() As String = File.ReadAllLines(_inifile)
Public _ini(IniLines.Length - 1)() As String
For I As Integer = 0 To IniLines.Length - 1
_ini(I) = IniLines(I).Split("="c)
Next
'.....code
Dim _tempini(Lines.Length - 1, SQSIZE - 1) As String
Dim tagrow As Integer
Dim tagcol As Integer
Dim taglist() As String
Dim RowSel As Integer = 1
Dim cControl As Control
For Each cControl In Me.Panel1.Controls
If cControl.Tag <> Nothing Then
taglist = Split(cControl.Tag, ","c)
If taglist(0) = "Cell" Then
tagcol = Val(taglist(1))
tagrow = Val(taglist(2))
If tagrow <= RowSel Then
If tagcol = 0 Then
_tempini(tagrow, tagcol) = _ini(tagrow)(tagcol)
Debug.WriteLine("Lower or equal then Selected row. 1st Column. From ini to row:" & tagrow)
' EDIT etc etc... more code here
Next cControl
' DIFFERENT CODE TRIED AT THIS STAGE to transfer from one array to the other:
ReDim _ini(Lines.Length - 1)
For countrow As Integer = 0 To _tempini.GetLength(0) - 1
For countcol As Integer = 0 To _tempini.GetLength(1) - 1
_ini(countrow) = _tempini(countrow)._tempini(countcol)
Next
Next
' Produces: Error 2 Number of indices is less than the number of dimensions of the indexed array.
ReDim _ini(Lines.Length - 1)
For countrow As Integer = 0 To _tempini.GetLength(0) - 1
For countcol As Integer = 0 To _tempini.GetLength(1) - 1
_ini(countrow)(countcol) = _tempini(countrow, countcol)
Next
Next
'Produces: Additional information: Object reference not set to an instance of an object.
正如我所说的,我甚至不确定我是否使用不用于“_ini”的列表Visual Studio上的Locals窗口将变量显示为:
_ini is "String()()"
_tempini is "String(,)"
我越来越意识到我需要回到vb的基础知识并学习所有涉及的概念。然而,一个快速的帮助将让我尝试完成这件事,我正在用蓝色大头钉和字符串敲开:)
答案 0 :(得分:0)
您实际上正在使用数组。列表的声明如下:
Dim myList As New List(Of String)()
列表总是有一个维度,列表的初始大小为0(除非您将枚举传递给构造函数)。您必须使用Add
方法逐个添加项目。这使得列表动态增长。
我认为你的ini文件看起来像这样
key1 = value1
key2 = value2
key3 = value3
此外,我假设该值不包含等号,否则我会查找等号的第一个实例,将字符串拆分为&#34;手动&#34;。
使用二维数组似乎不适合存储键值对。如果需要字符串或列表,可以使用方便的结构KeyValuePair(Of TKey, TValue)
。使用KeyValuePairs数组的优点是您不必处理二维数组。
但是,如果要查找给定键的值,Dictionary(Of TKey, TValue)
更合适,因为它针对非常快速的查找进行了优化。
Dim dict As New Dictionary(Of String, String)
For i As Integer = 0 To IniLines.Length - 1
Dim parts = IniLines(i).Split("="c)
dict.Add(parts(0).Trim(), parts(1).Trim())
Next
然后你可以检索这样的值
Dim value As String
If dict.TryGetValue("some key", value) Then
' Use the value
Else
' Sorry, key does not exist
End If
或者,如果您确定要查找的密钥确实存在,则可以编写
value = dict("some key")
答案 1 :(得分:0)
TLDR
(1)使用阵列...
(2)为什么要获得&#34;对象引用 未设置为对象的实例。&#34;
(3)多维数组 和阵列阵列
(4)你为什么得到&#34;指数是 小于维数...&#34;
(5)如果我是这样,我会怎么做 你...
(1)声明是指你写一个变量的名称及其类型。然后,您可以在代码中访问由此变量引用的对象。
(2)我们可以在创建实际对象并在内存中的某处注册时讨论(变量/对象)实例化。然后,您可以通过指向该对象的东西来操纵该对象:变量。
声明并不总是意味着创建了实际的对象。 (我不会在ValueType和ReferenceType中挖掘,对不起,我只是在解释事情时偷工减料而没有严格的dotNet复杂详细信息)
数组声明与instanciation不同:
Dim myArray As String()
这只是一个声明。您的阵列目前没有任何内容,因此不包含任何内容。调用myStringVariable = myArray(0)
之类的东西会抛出异常(对象引用未设置为对象的实例)意味着您的数组声明指向无处,因为您没有&#39 ; t创建了一个String()
类型的对象,并使您的Array声明指向该对象。
Dim myArray() As String
这与上述声明相同。哪一个是正确的?我不知道,这是一个品味问题。 VB以让你按照自己想要的方式做事而闻名。如果你做得好,你就可以像呼吸那样使用其中一种。事实上,我真的不在乎。
Dim myArray As String() = new String() {}
这只是数组的 instanciation 。您的数组已在内存中注册,但长度为0(零)且包含无单项(Length = 0
)。
记得上面的声明? (myArray() As String
或myArray As String()
)事实上,当您谈到实例化时,两种语法存在差异:
Dim myArray(3) As String
Dim myArray As String(3)
后者引发异常。变量type(String)不能有索引分隔符。
Dim myArray(3) As String '...
...还声明了一个数组并实例化它有4个预定义的项目,如下所示。
Dim myArray As String() ' this is a declaration.
Redim myArray(3) ' this is an instanciation with a defined size.
这是使用Redim
关键字定义数组中项目数的另一种方法。你有4&#34;插槽&#34;在索引[0]到索引[3]的数组中。你的数组看起来像这样:
[0][""]
[1][""]
[2][""]
[3][""]
Dim myArray As String = New String(3) {}
这与上面相同,但是在一行中:你要声明并实现一个包含4个String类型的String数组,这些都是空字符串(它们不是没有)
Dim myArray() As String = { "One", "Two", "Three", "Four" }
这是一行声明,实例化和项目设置:
[0]["One"]
[1]["Two"]
[2]["Three"]
[3]["Four"]
Redim用于重新定义数组中的项目数。一维数组就像它们应该的那样。
假设您已将数组定义为:
Dim myArray() As String = { "One", "Two", "Three", "Four" }
显然,你有四个String。然后使用Redim:
Redim myArray(6) ' to get 7 items ..!
这就是你得到的:
[0][""]
[1][""]
[2][""]
[3][""]
[4][""]
[5][""]
[6][""]
您可以调整数组的大小,但要将项目保留在内,您必须使用关键字: Preserve
Redim Preserve myArray(6)
myArray(4) = "Five"
'myArray(5) = "Six"
myArray(6) = "Seven"
因为我已经注释掉了第六项的设置,所以数组将如下所示:
[0]["One"]
[1]["Two"]
[2]["Three"]
[3]["Four"]
[4]["Five"]
[5][""] ' Empty String.
[6]["Seven"]
如果您在杀死某些项目时Redim保留数组上面两次会发生什么?
Redim Preserve myArray(2)
Redim Preserve myArray(6)
' You get :
[0]["One"]
[1]["Two"]
[2]["Three"]
[3][""]
[4][""]
[5][""]
[6][""]
你丢失了物品3..6!不要期望让他们回来。
这段代码的作用是什么?写Dim myArray(3)() As String
(&#34; 3&#34;可以是任何正整数或空整数)会产生以下数组结构:
[0][Nothing]
[1][Nothing]
[2][Nothing]
[3][Nothing]
为什么要获得Nothing
而不是二维数组?甚至不是空字符串?
这是因为上面的声明创建了一个 ONE 维数组数组(已定义类型,此处为String)
VB.net允许你以这种方式声明一个Array数组(我不知道C#是否可以 - 但我真的不在乎:我从来没有,也永远不会使用这种类型的语法)这不是二维数组。要定义值,您必须为每个项目(或行)创建包含的数组的每个实例,并将其分配给您的数组。
在上面的声明中,当你明确地初始化你的数组时,它的内容[0..3]仍然是简单的声明,指向没有任何实例,因此,解释了&#34; Nothing&#34;的事情。
然后从您的文件中获取数据后,您的_ini变量可能如下所示,具体取决于您的文件内容(这就是我要求您提供文件内容样本的原因):
[0][ ["Key0" | "Value0"] ]
[1][ ["Key1" | ""] ]
[2][ [""] ]
[3][ ["Key3" | "Value3" | "OtherData" | "MoreData" | "EvenMoreData"] ]
...
读取(String)值可以完成如下:
Dim myStringVariable As String = _ini(0)(1) ' Gets "Value0"
=&GT;使用Array或Arrays时要小心 多维数组。他们不一样!
让我们选择以下代码:
ReDim _ini(Lines.Length - 1)
For countrow As Integer = 0 To _tempini.GetLength(0) - 1
For countcol As Integer = 0 To _tempini.GetLength(1) - 1
_ini(countrow)(countcol) = _tempini(countrow, countcol)
Next
Next
您的_tempini
是字符串的双向数组
您的_ini
是一个String数组的一维数组
扫描这一行:
_ini(countrow)(countcol) = _tempini(countrow, countcol)
1)_ini(countrow)
包含Nothing (无论countrow的值是多少)=包含NO Array(of String),因为您之前刚刚调用ReDim _ini(Lines.Length - 1)
对于循环。
2)因此,您的分配_ini(countrow)(countcol) = ...
与在运行时运行以下内容相同:
Nothing(countcol) = _tempini(countrow, countcol)
没有什么不是数组,所以(countcol)索引没有意义:你将项目值索引到一个预期不存在的数组的对象。
这就是为什么你得到的异常 对象引用未设置为对象的实例 。
上述申报和实施仍然适用!
Public myBiDiArray(,) As String ' Declaration ONLY : bi dimensional array
Public myBiDiArray(2,1) As String ' Declaration AND Instanciation
Public myBiDiArray(,) As String = New String(2, 1) {} ' Dec. + Inst.
Public myBiDiArray(,) As String = _
{ {"One", "Un"}, {"Two", "Deux"}, {"Three", "Trois"} }
' ^^ Declaration + Instanciation + Item Setter
Public myBiDiArray(,) As String = _
New String(,) { {"One", "Un"}, {"Two", "Deux"}, {"Three", "Trois"} }
' ^^ Declaration + Instanciation + Item Setter
让我们有一个带有行和列的字符串的二维数组...
Dim myArray(2, 1) As String ' 3 lines, two columns
此数组包含以下项目:
Line 0 = [""][""]
Line 1 = [""][""]
Line 2 = [""][""]
现在您要调整数组大小并使用Redim(仅限)关键字...
Redim myArray(5, 3) ' ...
...将行设置为6,将列设置为4:
' Array Size = 6, 4
Line 0 = [""][""][""][""]
Line 1 = [""][""][""][""]
Line 2 = [""][""][""][""]
Line 3 = [""][""][""][""]
Line 4 = [""][""][""][""]
Line 5 = [""][""][""][""]
太棒了! 现在让我们在Row(0)和Column(0)
中设置一个值myArray(0, 0) = "Cell,0,0"
' You get :
Line 0 = ["Cell,0,0"][""][""][""]
Line 1 = [""] [""][""][""]
Line 2 = [""] [""][""][""]
Line 3 = [""] [""][""][""]
Line 4 = [""] [""][""][""]
Line 5 = [""] [""][""][""]
但保留关键字会怎样?
Redim Preserve myArray(3, 2) ' 4 lines and 3 columns
你得到一个例外:&#39; ReDim&#39;只能改变最右边的维度。
但您必须知道,除非您明确编写封装Try/Catch
代码的Redim Preserve
例程,否则调试器不会处理此异常。否则,应用程序只是退出包含该段代码的方法/函数而没有任何警告,并且您的数组保持不变!
要 redim 多维数组(不仅是最后一个维度),而保留其内容,您必须创建一个所需大小的新数组并复制该内容前一个到这个新阵列,然后让你的前阵列指向新的...
我在VB.Net中不知道这种语法。也许你从另一种语言或者一个Reference中获得了这个,它为数组增加了扩展(比如System.Linq),它为了某种目的将数组的成员扩展(?)为自己 ..但是我&#39 ;我没有意识到这一点。
它看起来像一个简单的语法错误。这就是为什么你得到例外 索引数量小于索引数组的维数。
要获取二维数组的(字符串)值,只需写入:
myStringValue = _tempini(countrow, countcol)
错误警告并未指向systax错误:调试器在关闭backet处停止并丢弃剩余的文本:
_ini(countrow) = _tempini(countrow ... ' <- compiler expects a comma here.
写这个会产生以下错误:
myStringValue = _tempini(countrow, countcol)._tempini(countcol)
编译器错误:&#39; tempini&#39;不是&#39; String&#39; 的成员。
同样,不要混淆双向数组和数组数组:写作......
_ini(countrow) = _tempini(countrow, countcol) ' ...
......没有意义!即使语法看起来正确,上面的代码实际上也会尝试将String
值分配给Array(Of String)
变量,这会抛出 InvalidCastException 。
我说实话:使用固定/预定义的尺寸/尺寸,阵列非常有趣。从我在运行时处理未知数量的元素/项目的那一刻开始,我将数组放在之后。
哦!同样Olivier Jacot-Descombes建议你这样做:)毫不奇怪,Dictionary
在你的情况下非常方便。
我也会启用这两个:
Option Strict On
Option Explicit On
并停用此项:Option Infer Off
。
另一个 PERSONAL 建议是避免使用控件的Tag属性。此标记的类型为Object
。
Date
甚至Nothing
的特定控件。为什么?因为我混淆了两个不同的项目并且忘记了整个事情。Objects
的代码的模糊底层逻辑。人们喜欢处理强类型变量,易于调试并在运行时快速执行。同时避免使用Val()
。 Val()非常方便,因为它几乎可以转换任何东西。但是,由于这个很好的功能,它会在CPU上增加工作量。同样,如果您知道自己正在处理Int32
或Double
,那么请使用Int32.Parse()
或Double.Parse()
,而不是Val()。 Web上大多数滥用Val()与类型推断和隐式转换有关。调试这种故障是一种真正的痛苦。只有在没有其他选择时才使用Val。
我认为您现在几乎拥有了所需的一切,以使您的代码能够进行少量更改。我没有提供更改的代码:
^^所以我只谈了两件事:
那是你寻找的(不那么)快速助手吗?我不知道。这是我现在能做的最好的。
答案 2 :(得分:0)
行。人们真的很有帮助,但在这个阶段并没有完全重新编码。然而,我找到了一个解决方案。它不是很漂亮,可能是真的糟糕的做法!但是,使用我得到的代码运行并运行。
基本上,我只是反向完成了这个过程,从_tempini中的组件构造了一行,用“=”分隔,然后重新运行原始过程,首先填充_ini数组。一个完整的解决方案,但希望将帮助像我这样的其他业余爱好者陷入这些早期阶段。
但是,我会说遵循这些fellas建议!在启动代码之前查看列表,词典等。
修复:
ReDim _ini(((_tempini.Length) / 2) - 1)
Dim _newiniline As String
_newiniline = ""
For countrow As Integer = 0 To (((_tempini.Length) / 2) - 1)
For countcol As Integer = 0 To 1
_newiniline = _newiniline & _tempini(countrow, countcol)
If countcol = 0 Then
_newiniline = _newiniline & "="
End If
_ini(countrow) = _newiniline.Split("="c)
Next
_newiniline = Nothing
Next