ReadOnly Property Gets "Unintentional" Change - arrays

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

Related

Setting a string to be empty if value is null

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 & "",

How to pass value from one window to another

How do I pass a value from one a variable to a textbox after it's set? On winforms, I used to use form1.textbox1.text = variable in winforms.
I set, and get the variable from this...
Public Shared Property containerstring() As String
Get
Return m_containerstring
End Get
Set(value As String)
m_containerstring = value
End Set
End Property
Private Shared m_containerstring As String
Basically, I have a window... where the user chooses a variable, this variable is then set # containerstring. When this form closes, I wanted to push this variable to the currently open window's textbox.
I'm new to WPF, forgive the noobness.
This is how I do it for a window, and this works perfectly... for windows. I'm looking to do the same thing with a control.
Dim strWindowToLookFor As String = GetType(MainWindow).Name
Dim win = ( _
From w In Application.Current.Windows _
Where DirectCast(w, Window).GetType.Name = strWindowToLookFor _
Select w _
).FirstOrDefault
If win IsNot Nothing Then
DirectCast(win, MainWindow).Title = SelectedContainer
End If
You can make a Window closing Event like :
this.Closed += MyWindow_Closed;
and then set your variable in the corresponding method.
private void MyWindow_Closed()
{
TextBox1.Text = a;
}
You could use a PubSubEvent which is available in Prism.Events. This will allow you to subscribe to events.
Using Prism.Events;
define your Event.
public class MyEvents : PubSubEvent<object>
{
public MyEvents();
}
In your first window or code behind
[Import]
public IEventAggregator EventAggregator
{
get;
set;
}
and you can use this property in your program to send whatever value you want to send.
For example
private void MyWindow_Closed()
{
MyEvents myEvents = EventAggregator.GetEvent<MyEvents>();
myEvents.Publish(yourvalue);
}
Once you have publised you can Subscribe to the same event in any other part of your program like this.
MyEvents myEvents = EventAggregator.GetEvent<MyEvents>();
myEvents.Subscribe(MyEventMethod, ThreadOption.UIThread, true);
and get your data here
void MyEventMethod(object obj)
{
// do wharever you want
}

Fill public array with values

Basic arrays question:
I have declared a public array and initialized it with values. In another private sub, I want to fill that public array with values. What is the easiest way to do it?
The double variables in the array are also declared public. The following code is the array created and initialized in a public module. In the private sub, I am changing the values of the double variables (ch0LowLmt, ch1LowLmt, etc, etc) and now I just simply want to reinitialize the array with the new values. What is the simplest way to do it?
Public AlarmLowLimit() As Double = New Double(15) {Ch0LowLmt, Ch1LowLmt, Ch2LowLmt, Ch3LowLmt, Ch4LowLmt, Ch5LowLmt, Ch6LowLmt, Ch7LowLmt, Ch8LowLmt, Ch9LowLmt, _
Ch10LowLmt, Ch11LowLmt, Ch12LowLmt, Ch13LowLmt, Ch14LowLmt, Ch15LowLmt}
Because Double is a value type, you do need to change it manually in the way you are working.
Another way, is to encapsulate the double var inside a class, which can be put inside your array, so it will be a reference type.
In this case you'd just update your new reference type objects in the private function you have mentioned. They will also change in your array.
See a nice solution here.
And the code example in Vb.Net:
Public Class MyObjectWithADouble
Public Property Element() As Double
Get
Return m_Element
End Get
Set
m_Element = Value
End Set
End Property
Private m_Element As Double
' property is optional, but preferred.
End Class
Dim obj = New MyObjectWithADouble()
obj.Element = 5.0

Creating Property Get/Let procedures for a private array

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.

et Return the Whole Subdocument Arrary from MongoDB

I need to get all of the subdocuments array from the Courses Class where the User.UserId = whatever and Courses.Status=active
Public Class User
Public Property UserId As String 'this is unique so i would like to index this, unless you think otherwise
Public Property CourseData() As List(Of Courses) '
Public Property Groups As List(Of String)
Public Property BU As List(Of String)
End Class
Public Class Courses
Public Property id As String 'this can be dynamic
Public Property description As String
Public Property CompletionDate As String
Public Property Hours As String
Public Property Status As String
End Class
Using vb.net , I tried a few ways, I only want the courses returned that have a Status="Active" to be dumped into Ienumberable
I tried (_users is a collection of User) (_uid is a variable passed into it)
Return _users.FindAs(Of User)(Query.And(query.EQ("LearningHours.Status", "Active"), (Query.EQ("UserId", _uid))))
Return _users.FindAs(Of User)(Query.And(query.EQ("LearningHours.Status", "Active"), (Query.EQ("UserId", _uid)))).SetFields("Courses", "1")
Return _users.FindAs(Of Courses)(Query.And(query.EQ("LearningHours.Status", "Active"), (Query.EQ("UserId", _uid))))
Return _users.FindAs(Of Courses)(Query.And(query.EQ("LearningHours.Status", "Active"), (Query.EQ("UserId", _uid)))).SetFields("Courses", "1")
None seem to work, they usually come back with the fields from Class User or both Class User and Class Course, but the Course fields are blank
I even am trying linq.. this works - but only returns 1 row result
Dim uc = From _u In _users.AsQueryable(Of User)()
Where _u.userid = _userid _
Select _
CourseID = _u.Courses.Where(Function(c) c.State = "Submitted").Select(Function(c) c.CourseId)(0), _
CourseDescription = _u.Courses.Where(Function(c) c.State = "Submitted").Select(Function(c) c.CourseDescription)(0)
Seems easy enough to do, just cant get it
Got It, I think I was over thinking it
Once I declare an instance of the class, I can iterate through the subdocument
Dim _u as new User
For Each c In _user.Courses.Where(Function(cs) cs.Status= "Active").Select(Function(cs) cs)
console.writeline(c.id & c.description & "so on...")
Next

Resources