I'm trying to find an alternative way to solve the problem I'm stuck on here. I'm using MSTest to select one of a set of arrays of bytes to pass to a function under test.
I'm trying this approach as I haven't been able to get MSTest working directly passing an array of bytes to the test function.
I want to set up a Private ReadOnly jagged array of arrays of Bytes (TestMsgs) as part of my test class to allow the test subroutine to access elements one by one. Currently I'm getting error BC30201 "Expression Expected" as below. Something is missing in my initialisation, but I can't find any example on how to initialise this jagged array.
Public Class DecoderTests
Private ReadOnly TestMsgs As Byte()() = New Byte(2)() {
New Byte() {&HA1, &HB2, &HC3}, 'Test array should Pass
New Byte() {&HA2, &HB3}, 'Test array should Fail
} <========= Error BC30201 Here
Private DecoderInstance
Here is the full code of my test (Simplified to debug the original issue)
Test Class
Imports System.Text
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Namespace TestDecoder.Tests
<TestClass>
Public Class DecoderTests
Private ReadOnly TestMsgs As Byte()() = New Byte(2)() {
New Byte() {&HA1, &HB2, &HC3}, 'Test array should Pass
New Byte() {&HA2, &HB3}, 'Test array should Fail
}
Private DecoderInstance
<DataTestMethod>
<DataRow(0)>
<DataRow(1)>
Public Sub ParseTestData(message_number)
Dim result As Boolean
DecoderInstance = New Decoder()
result = DecoderInstance.parse(TestMsgs(message_number)(0))
Assert.IsTrue(result, "Failed the dummy test")
End Sub
End Class
End Namespace
Simplified Class under test:
Imports Microsoft.VisualBasic
Public Class Decoder
Function parse(rxchar As Byte) As Boolean
Return rxchar = &H41
End Function
End Class
I just tried this code and there were no errors:
Private ReadOnly TestMsgs As Byte()() = {
New Byte() {&HA1, &HB2, &HC3},
New Byte() {&HA2, &HB3}
}
I think the issue with your original code was that you were specifying the size of the array explicitly and also initialising it, therefore specifying the size of the array implicitly. I just tested this code and it worked too:
Private ReadOnly TestMsgs As Byte()() = New Byte()() {
New Byte() {&HA1, &HB2, &HC3},
New Byte() {&HA2, &HB3}
}
I am not sure how to search for the issue I am trying to solve here. In the program I am writing (in VB.Net) I am trying to assign values pulled from a database to different variables in a structure.
Now my issue is that sometimes, some of the values pulled from the database are NULL, for example not every phone number has an extension. This is what I have for my code at the moment:
Structure CustomerContact
Public _name As String
Public _email As String
Public _fax As String
Public _phone1 As String
Public _phone2 As String
Public _phone3 As String
Public _ext1 As String
Public _ext2 As String
Public _ext3 As String
Public _type1 As String
Public _type2 As String
Public _type3 As String
End Structure
Dim contactData As DataTable = CustomerDBFunctions.GetCustomerContacts(Customer)
For Each row As DataRow In contactData.Rows
If contacts.Count < 1 Then
contacts.Add(New CustomerContact With {
._name = row.Item("FullName").ToString() & " (" & row.Item("ContactType").ToString() & ")",
._email = row.Item("Email").ToString(),
._fax = row.Item("Fax").ToString(),
._phone1 = row.Item("Phone").ToString(),
._ext1 = row.Item("Extension").ToString(),
._type1 = row.Item("PhoneType").ToString()})
End If
Next
Right now I am getting an error when the value in the database is NULL because it can't assign a NULL value to a string. I'd like to in the instances where a NULL value is present instead set the value of the variable to "" instead. I am just unsure how to code this.
Technically, the problem isn't that the column is null. String is a reference type, so it can but null (though, if it was null, you wouldn't be able to call ToString on it anyway). What's actually going on is that ADO.NET always returns DBNull.Value for all columns where the row contains a null value.
You could check it, like this:
If row.Item("Phone") <> DBNull.Value Then
customerContact._phone1 = row.Item("Phone")?.ToString()
End If
Note, I used ?. instead of . when calling ToString just in case the column actually is null rather than DbNull.Value. The reason for this is that I don't know what kind of code you're using to fill that DataTable. If it's ADO.NET that's filling it, it'll never be null, but if it's custom code that populates it via some other means, it might get actual nulls in it.
Since you are using a DataTable to return the value, it has a convenient IsNull method that you can use, which cleans up the code a little bit:
If Not row.IsNull("Phone") Then
customerContact._phone1 = row.Item("Phone")?.ToString()
End If
Obviously, if you're doing this a lot, it would be good to wrap it up into a reusable function. Also, if you want to shorten it up into one line, you could do so like this:
._phone1 = If(row.IsNull("Phone"), row.Item("Phone")?.ToString(), Nothing)
String concatenation can be used to convert Nothing to "" (other alternatives in my answer here)
._fax = row!Fax & "",
I have an array called lblTables which contains 21 lables of my form. This works perfectly fine. The code for it is below:
Public lblTables() As Label
Public Sub New()
InitializeComponent()
lblTables = New Label() {Label2, table1, table2, table3, table4, table5, table6, table7, table8, table9, table10,
table11, table12, table13, table14, table15, table16, table17, table18, table19, table20}
End Sub
I need to create another array called lblStartTimes which will contain another 21 labels. So i proceeded as follows:
Private lblStartTimes() As Label
Public Sub New()
InitializeComponent()
lblStartTimes = New Label() {startTime1, startTime2, startTime3, startTime4, startTime5, startTime6,
startTime7, startTime8, startTime9, startTime10, startTime11, startTime12, startTime13, startTime14,
startTime15, startTime16, startTime17, startTime18, startTime19, startTime20}
End Sub
But when i tried to do that i got an error saying Public Sub New() has multiple definitions with identical signatures. So after doing a research i found the easiest way of doing this would be as follows:
Public lblStartTimes() As Label = {Label3, startTime1, startTime2, startTime3, startTime4, startTime5, startTime6,
startTime7, startTime8, startTime9, startTime10, startTime11, startTime12, startTime13, startTime14,
startTime15, startTime16, startTime17, startTime18, startTime19, startTime20}
but when i use this method i'm constantly receiving a System.NullReferenceException error. i need to declare lblStartTimes the same OR similar way i declared lblTables array without getting the multiple definitions error. How can i achieve this?
Like already suggested in the comments, you are allowed to write multiple lines in the constructor. Just move the second array initialization code to the first constructor:
Public lblTables() As Label
Public lblStartTimes() As Label
Public Sub New()
InitializeComponent()
lblTables = New Label() {Label2, table1, table2, table3, table4, table5, table6, table7, table8, table9, table10,
table11, table12, table13, table14, table15, table16, table17, table18, table19, table20}
lblStartTimes = New Label() {startTime1, startTime2, startTime3, startTime4, startTime5, startTime6,
startTime7, startTime8, startTime9, startTime10, startTime11, startTime12, startTime13, startTime14,
startTime15, startTime16, startTime17, startTime18, startTime19, startTime20}
End Sub
I am trying to assign a number of values to a private array in a class module using public Property Get/Let procedures. But when I try to get the values out, the array is showing as empty. Why is this?
Here's the relevant code:
Private pdt_RentStepDate(23) As Date
Public Property Get dt_RentStepDate(ByRef d1 As Integer) As Date
dt_RentStepDate(d1) = pdt_RentStepDate(d1)
End Property
Public Property Let dt_RentStepDate(ByRef d1 As Integer, something As Date)
pdt_RentStepDate(d1) = something
End Property
In your Property Get procedure, don't specify an index when you're assigning the return value:
Public Property Get dt_RentStepDate(ByRef d1 As Integer) As Date
' dt_RentStepDate(d1) = pdt_RentStepDate(d1) ' <-- WRONG
dt_RentStepDate = pdt_RentStepDate(d1) ' <-- RIGHT
End Property
If you specify an index, then instead of assigning the return value for the Property Get, you're actually calling the Property Let with the arguments d1 and pdt_RentStepDate(d1). (This has no effect because the Property Let ends up setting pdt_RentStepDate(d1) to itself.) Since no return value is assigned, the Property Get always returns an empty Date.
I understand that List, Array, Object etc. types "copied" by reference. However my natural and ordinary intend is to just have a "copy" of it in this context where I intentionally use ReadOnly instead of Read/Write property. In below sample the ReadOnly 'Extensions' property get change through 'm_extensions' reference change. Regardless, I think this behavior is incorrect and I have to do extra work to prevent ReadOnly properties from being overwritten. Is there any built in keyword to use for 'm_extensions' value protection?
Public Classs A
' more properties and methods here...
Private m_extensions() As String = {"*.abc", "*.def"}
Public ReadOnly Property Extensions() As String()
Get
Return m_extensions
End Get
End Property
End Class
Public Classs B
' more stuff here...
Private Function BuildFilter() As String
Dim l() As String = A.Extensions
Dim s As String = String.Empty
For m As Integer = 0 To l.Length - 1
Select Case l(m).ToLower
Case "*.*" : s = "All Files"
Case "*.abc" : s = "ABC File"
Case "*.def" : s = "DEF File"
Case Else : s = "XYZ File " + m.ToString
End Select
l(m) = String.Format("{1} ({0})|{0}", l(m), s)
Next
Return String.Join("|", l)
End Function
End Class
Readonly modifier means that anything using the property cannot change the reference that you protected this way (e.g. cannot set it to Nothing). It doesn't prevent changing the values in the array returned from that property.
One way around it could be to copy the array inside the property. This will prevent modifications of the original array:
Public ReadOnly Property Extensions() As String()
Get
Return m_extensions.Clone()
End Get
End Property