How do I change a string / remove the quotations to make it a existing object value instead of string? I've got a constant object that is used to input what the "currentcreature" is which's value is inputted into byVal tables but whenever I try inputting it as the result of a SQL table search is a string I do not know how to put the string result turning into an object.
Dim Placeholder As New List(Of Object)
Sub with stuff
another sub that ends with this
Placeholder.Add(SearchResults.GetString(0))
CurrentCreature = Placeholder(0)
LoadCreature(CurrentCreature, Player)
End sub
Object of the Constant CurrentCreature immediately gets an error with the preceding code
Value of Creature should be Object rather than String
Creature "Frog" Object {String}
What should happen:
CurrentCreature sure be able to apply with the object as its input than string (this works normally if I put it equal to any object so I mainly want to figure out how to change the values of strings into datatype object/gain the values of it initially stored as objects)
Related
I was wondering if there is any way to access the expected data type within a function similar to an event arg. I am doubtful that this is possible, though it would be an excellent feature.
I frequently work with (old and disorganized)Mysql databases creating interfaces through VB.Net. Often I will have an optional field which contains a NULL value in the database. I am frequently dealing with errors due to NULL and dbnull values in passing data to and from the database.
To complicate things, I often am dealing with unexpected datatypes. I might have an integer zero, a double zero, an empty string, or a string zero.
So I spend a fair amount of code checking that each entry is of the expected type and or converting NULLs to zeros or empty strings depending on the case. I have written a function ncc(null catch convert) to speed up this process.
Public Function ncc(obj As Object, tp As Type) As Object 'Null Catch Convert Function...
My function works great, but I have to manually set the type every time I call the function. It would be so much easier if it were possible to access the expected type of the expression. Here is an example of what I mean.
Dim table as datatable
adapter.fill(table)
dim strinfo as string
dim intinfo as long
strinfo = ncc(table.Rows(0).Item(0),gettype(String)) 'here a string is expected
intinfo = ncc(table.Rows(0).Item(0),gettype(Long)) 'here a long is expected
It would be so much more efficient if it were possible to access the expected type directly from the function.
Something like this would be great:
Public Function ncc(obj As Object, optional tp As Type = nothing) As Object
If tp Is Nothing Then tp = gettype(ncc.expectedtype)
That way I do not have to hard code the type on each line.
strinfo = ncc(table.Rows(0).Item(0))
You can make the ncc function generic to simplify calling it:
Public Function ncc(Of T)(obj As T) As T
If DbNull.Value.Equals(obj) Then Return Nothing
Return Obj
End Function
This kind of function will be able to in some cases infer the type, but if there's any possibility of null you'll still want to include a type name (because DBNull will be the inferred type for those values). The advantage is not needing to call gettype() and so gaining a small degree of type safety:
strinfo = ncc(Of String)(table.Rows(0).Item(0))
But I think this has a small chance to blow up at run time if your argument is not implicitly convertible to the desired type. What you should be doing is adding functions to accept a full row and return a composed type. These functions can exist as static/shared members of the target type:
Shared Function FromDataRow(IDataRow row) As MyObject
And you call it for each row like this:
Dim record As MyObject = MyObject.FromDataRow(table.Rows(i))
But, you problem still exists.
What happens if the column in the database row is null?
then you DO NOT get a data type!
Worse yet? Assume the data column is null, do you want to return null into that variable anyway?
Why not specify a value FOR WHEN its null.
You can use "gettype" on the passed value, but if the data base column is null, then you can't determine the type, and you right back to having to type out the type you want as the 2nd parameter.
You could however, adopt a nz() function (like in VBA/Access).
So, this might be better:
Public Function ncc(obj As Object, Optional nullv As Object = Nothing) As Object
If obj Is Nothing OrElse IsDBNull(obj) Then
Return nullv
End If
Return obj
End Function
So, I don't care if the database column is null, or a number, for such numbers, I want 0.
So
dim MyInt as integer
Dim MyDouble As Double
MyInt = ncc(rstData.Rows(0).Item("ContactID"), 0)
MyDouble = ncc(rstData.Rows(0).Item("ContactID"), 0)
dim strAddress as string = ""
strAddress = ncc(rstData.Rows(0).Item("Address"), "")
Since in NEAR ALL cases, you need to deal with the null from the DB, then above not only works for all data types, but also gets you on the fly conversion.
I mean, you CAN declare variables such as integer to allow null values.
eg:
dim myIntValue as integer?
But, I not sure above would create more problems than it solves.
So,
You can't get exactly what you want, because a function never has knowledge of how it's going to be used. It's not guaranteed that it will be on the right-hand side of an assignment statement.
If you want to have knowledge of both sides, you either need to be assigning to a custom type (so that you can overload the assignment operator) or you need to use a Sub instead of an assignment.
You could do something like this (untested):
Public Sub Assign(Of T)(ByVal field As Object, ByRef destination As T,
Optional ByVal nullDefault As T = Nothing)
If TypeOf field Is DBNull Then
destination = nullDefault
Else
destination = CType(field, T)
End If
End Sub
I haven't tested this, so I'm not completely certain that the compiler would allow the conversion, but I think it would because field is type Object. Note that this would yield a runtime error if field is not convertible to T.
You could even consider putting on a constraint requiring T to be a value type, though I don't think that would be likely to work because you probably need to handling String which is a reference type (even though it basically acts like a value type).
Because the destination is an argument, you wouldn't ever need to specify the generic type argument, it would be inferred.
I am trying to add rows to a datagridview and when loading the from it only displays one letter on the variable I am trying to retrieve.
Dim col As New DataGridViewTextBoxColumn 'adding the colunm player to the data grid view
col.HeaderText = "Player"
DataGridView_displayfigures.Columns.Add(col)
DataGridView_displayfigures.Rows.Add(New String({AssignRuns.batsman1A}))
This is the structure
Structure AssignRuns
Shared batsman1A As String = PlayerSelection.player1_cmbox.Text
Shared batsman1Aruns As Integer
I don't understand this. any help would be appreciated
This is a perfect example of why you should have Option Strict On. You are use a String constructor here:
DataGridView_displayfigures.Rows.Add(New String({AssignRuns.batsman1A}))
But that is definitely not doing what you intend. You are passing a String array as an argument but there is no String constructor that has a parameter of type String array. With Option Strict On, that would generate a syntax error and your code would fail to compile until you fixed it.
With Option Strict Off, the compiler looks for a constructor that is similar enough that it can massage your code to work. In this case, it uses the one that has a parameter of type Char array. That constructor creates a String containing all the Char values from the array.
In your case, each String in your array is converted to a Char by simply taking the first character in each String. Your array only contains one String so only one Char is passed to the constructor, so the String that gets created only contains one character.
As well as that, there's no overload of that Add method that takes a single String either. There is one that takes an Object array though, so that's what you should be passing:
DataGridView_displayfigures.Rows.Add(New Object() {AssignRuns.batsman1A})
This would also work:
DataGridView_displayfigures.Rows.Add({AssignRuns.batsman1A})
That is technically passing a String array to the Add method but that is allowed because it's a widening conversion, i.e. no data can be lost. Converting a String to a Char is a narrowing conversion because data can be lost, as it was in your original code. Option Strict On allows implicit widening conversions but not implicit narrowing conversions.
EDIT:
Actually, thinking about that last code snippet and the fact that you can pass a String array directly to Add makes me think that maybe your mistake was just to misplace a single closing parenthesis because, rather than this:
DataGridView_displayfigures.Rows.Add(New String({AssignRuns.batsman1A}))
you could have had this:
DataGridView_displayfigures.Rows.Add(New String() {AssignRuns.batsman1A})
Moving that closing parenthesis means that you are denoting a String array and then initialising it, rather than passing a literal String array as an argument to a constructor.
You can try me this way to add rows and columns in the DataGridView control.
Public Class Form1
Structure AssignRuns
Shared batsman1A As String = "player1"
Shared batsman1Aruns As Integer = 3
End Structure
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'definite columncount and then add columns of datagridview1
DataGridView1.ColumnCount = AssignRuns.batsman1Aruns
DataGridView1.Columns(0).HeaderText = "Player"
'add rows of datagridview1
Dim row As String() = {AssignRuns.batsman1A} 'You can try {AssignRuns.batsman1A,AssignRuns.batsman1A,AssignRuns.batsman1A}
DataGridView1.Rows.Add(row)
End Sub
End Class
This question already has answers here:
Argument passed ByVal to VB.NET Function and manipulated there
(2 answers)
Closed 4 years ago.
The list value changeed here when passed ByVal why
,it must be not changed.
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
Dim value As Integer = 1
Dim value2 As New List(Of Decimal)
value2.Add(1)
value2.Add(2)
' The integer value doesn't change here when passed ByVal.
Example1(value)
Console.WriteLine(value)
' The list value changeed here when passed ByVal.
Example3(value2)
Console.WriteLine(value)
End Sub
Sub Example1(ByVal test As Integer)
test = 10
End Sub
Sub Example3(ByVal test As List(Of Decimal))
test.Add(3)
End Sub
its solved ,the solution is making new copy:
Sub Example3(ByVal test As List(Of Decimal))
Dim testnew As New List(Of Decimal)
testnew.AddRange(test)
testnew.Add(3)
End Sub
You need to do some reading on value types and reference types and passing method arguments by value and by reference. They are related but not the same thing. When you pass a method argument by value, you create a copy of the variable being passed. If the variable is a value type, i.e. a structure, then that means creating a copy of the value. If the variable is a reference type, i.e. a class, then that means creating a copy of the reference. The thing is, the original reference and the copy still both refer to the same object.
The reason that reference types exist is that you wouldn't want to create copies of large objects every time you assigned them somewhere. In the case of passing a collection to a method, it's almost always the case that any change you make inside the method you will want to be reflected outside. In the rare case that you don't, it's up to you to create a copy of the collection first and pass that in.
When you pass a value type by value, you create a copy of the value. That means that no changes you make inside the method can affect the original variable. You can assign a new value to the parameter or you can set a property of the value and the change will not be reflected outside the method. Of course, value types should generally be immutable and so setting a property should not be possible, but there are times that that "rule" gets broken.
When you pass a reference type by value, you create a copy of the reference. That means that assigning a different object to the parameter inside the method will not affect the original variable. There is still only one object though, referred to by the original variable and the parameter. As such, if you set a property of that object via the parameter then that change will be reflected in the original variable, because it's the same object.
When you pass a value type by reference, you create a new reference to the value. That means that any changes you make inside the method will affect the original variable. You can assign a new value to the parameter or you can set a property of the value and the change will be reflected outside the method.
When you pass a reference type by reference, you create a new reference to the original reference. That means that assigning a different object to the parameter inside the method will affect the original variable. There's still just one object, so setting a property on the parameter will still affect the original variable too.
Those are the only four possibilities: value type by value, reference type by value, value type by reference and reference type by reference. In none of those scenarios is a copy of a reference type object made so in none of those scenarios can you set a property of a reference type object via a method parameter and have that change not be reflected in the original variable.
If you want a copy of the original object then it's up to you to create one explicitly. Whether you do that inside the method or outside really depends on the specific circumstances. That means that you need to change your code to this:
Sub Example3(ByVal test As List(Of Decimal))
Dim copy = test.ToList()
copy.Add(3)
End Sub
or this:
Dim copy = value2.ToList()
Example3(copy)
Let me just repeat the important point here: there is NO WAY to pass a reference type object to a method, modify the object via the parameter inside the method and have that not affect the original variable (assigning a different object to the parameter is NOT modifying the object). If you want a modification inside the method to not affect the original variable then you need a copy of the object and the ONLY way that will happen is if YOU do it explicitly.
I want to be able to allow the user to input a string and then use that string to create a different variable. For example:
Dim UserInput As String
UserInput = Console.Readline()
Dim (UserInput) As String
So if the user input "Hello" a new variable called 'Hello' would be made.
Is this possible and if not, are there any alternatives?
The names of variables must be known at compile-time. What you're asking for here is to wait until run-time to know the name. That just doesn't work
What you can do is use a Dictionary(Of String, String) to hold your data.
This code works:
Dim UserInput As String
UserInput = Console.Readline()
Dim UserInputData As New Dictionary(Of String, String)
UserInputData(UserInput) = "Some Value"
Console.WriteLine(UserInputData(UserInput))
So if you enter Bar then the dictionary has this value in it:
The bottom-line is that everything is known at compile-time, but you can store data based on the user input at run-time.
It is currently not possible to dynamically create single variables in VB.net. However, you can use lists or dictionaries (source: Dynamically create variables in VB.NET)
The name of the variable does not matter to the user because they will never see it. They will only ever see the data it holds. There really is no reason for this
So I have a UDT set up like this:
Public Type UserInfo
name as string
username as string
active_time as double
End Type
I then create an array of this type:
Dim list_of_users() as UserInfo
'Populate array here
What I want to do is pass the active_time values as an array into a separate function. Something like:
'StdDev function defined elsewhere
standard_dev_all = StdDev(list_of_users().active_time)
Is this even possible? I suppose I could modify the function to deal with my UDT, but I have many more values than just active_time and it seemed like that would make it pretty messy.
You cannot pass it as
UDTvariable.Element
' or
UDTvariable().Element
into a function. I mean,
the first one is not valid as the index of the array element (not the element's Element) hasn't been specified.
The second one is invalid as well.
The solution is to pass on to your function
Answer = Stdev(UDTVariable)
and inside the function, you do this
Function Stdev(ByRef UDTVariableTypeName UDTVariable)
for i = 1 to N
Something = UDTVariable(i).Element
' so on and so forth
next i
Stdev = SomeAnswer
End Function
You may omit writing ByRef as that is the default way of passing arguments, but I've kept it for the sake of clarity.