Is there any way to get the parameters of a function dynamic?
Like:
Function(text As String, If text = "yes" text2 As String)
End Function
So the second one just gets asked, when the first is filled or a certain value?
Optional is no way, cause for example the third needs to be filled when the second one is already.
No, you can't do that. But you might accomplish something similar via Currying.
Currying takes a function that needs multiple arguments, and converts into a set of functions that each need a single argument, where prior functions in the set return the next function in the set.
Where this will still be problematic for your situation is .Net likes strongly-typed delegates. If the initial function needs to return a method with one argument for any case, it must do that for all cases.
However, that doesn't mean it returns the same function. You can still vary which function is returned based on the initial input argument.
So instead of this:
Function test(text As String, a As String) As String
If text = "yes" Then
Return text & a
Else
Return a & text
End If
End Function
test("yes", "foo") ' produces "yesfoo"
test("no", "foo") ' produces "foono"
We have this:
Function test(text As String) As Func(Of String, String)
If text = "Yes" Then
Return Function(a) text & a
Else
Return Function(a) a & text
End If
End Function
test("yes")("foo") ' produces "yesfoo"
test("no")("foo") ' produces "foono"
This won't do exactly what you want; it still requires the additional argument or not in every situation. But it might give you enough new flexibility to accomplish your ultimate goal. For example, perhaps you could combine this with a closure, where you never use the additional argument, but in the case where you need it the additional value is still available. Exactly how this will look or whether it's really possible or helpful will depend on the details of what you're trying to accomplish beyond the simple test code in the question.
You could handle what to pass in the button code.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim paramValue As String
If MyTestText = "yes" Then
paramValue = TextBox2.Text
Else
paramValue = TextBox1.Text
End If
End Sub
Private Function SomeFunction(text As String) As String
Dim ReturnValue As String = ""
'your code here
Return ReturnValue
End Function
Or you could pass both values and test in your Function code
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim ReturnedValue = SomeFunction(TextBox1.Text, TextBox2.Text)
End Sub
Private Function SomeFunction(text1 As String, text2 As String) As String
Dim ReturnValue As String = ""
If MyTestText = "yes" Then
'process text2
Else
'process text1
End If
Return ReturnValue
End Function
I am sure there are other ways to handle this.
Related
In the function below, what is the meaning of the & character? I'm not aware how it's valid syntax or how this would be used normally.
Normally using &= together would do a concatenation and assignment, resulting in "Hello world". However in this "typo" the code actually compiles but the result is just an assignment of " world" to the MyStr variable. Also if you define MyStr in the function rather than at the class level, the result is that it will not compile and interprets the & as a Type Character and fails because MyStr is a string and not of type Long.
Public Class MyClassName
Private MyStr As String
Public Sub New()
End Sub
Public Function MyFunction() As String
MyStr = "Hello"
MyStr& = " World"
Return MyStr
End Function
End Class
Microsoft admits it's a bug in the compiler.
It is not going to be fixed because that would be a breaking change.
As you mention, the & is acting as a type character. Type characters are essentially just a shorthand for declaring the type of a variable. For example, you could use
dim value& = 100 rather than dim value as Long = 100
They are generally used when defining a value on the fly, such as when passing a value to a function:
dim result = funcThatTakesALong(100&)
You can also see in the link that you posted there are also type characters for integers (%), decimals (#), singles (!), doubles (#), and strings ($).
Edit: formatting
I think this may explain the purpose of the operators
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
XYZ(9&) ' Long values
XYZ(9L)
XYZ(9I) ' Int32 values
XYZ(9%)
XYZ(9S) 'Int16 value
XYZ("9"c) ' a single charcter
XYZ("9") ' a string
End Sub
Sub XYZ(ByVal arg As Object)
Debug.Print("arg type is " & arg.GetType.ToString)
'do some stuff depends on the type of arg
End Sub
.
I keep getting this error, I tried all I could but it still says "Value type of String() cannot be converted to string."
Here is the code:
Private Sub Label1_Click(sender As Object, e As EventArgs) Handles Label1.Click
End Sub
Sub New()
InitializeComponent()
RAN = New Random
WB = New WebClient
End Sub
Private Const IDNum As String = "https://example.com/Data.php"
Private WB As WebClient
Private RAN As Random
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim Account As String() = WB.DownloadString(IDNum).Split(Environment.NewLine)
AccSplit(Account(RAN.Next(1, Account.Length)))
End Sub
Private Sub AccSplit(ByVal Account As String)
TextBox2.Text = Account.Split()
End Sub
When you call Split here:
TextBox2.Text = Account.Split()
You are getting a String array back. Calling Split with no arguments will split the String on whitespace characters. For instance, this:
Dim arr = "Hello World".Split()
is equivalent to this:
Dim arr = {"Hello", "World"}
The Text property of a TextBox is type String, so you can't assign a String array to it. That doesn't make sense. If you want to fry an egg, do you put am egg carton in the pan? The correct course of action depends on what you're actually trying to achieve. If you just want that String displayed in the TextBox then do this:
TextBox2.Text = Account
You could also do this:
TextBox2.Lines = Account.Split()
to display the array with the elements on separate lines in the TexTbox, which assumes that you have set its Multiline property to True.
TextBox2.Text is a string. The string.Split() function returns an array of strings (shown by Visual Studio as a string()). Those types don't match up. You can't just assign an array to a string. I might ask if you wanted this:
TextBox2.Text = String.Join(",", Account.Split())
That will at least compile. But it makes no sense... why split a string, just to join it back again?
I'm wondering if this is the right way to do this.
I have this sample code that should represent a user action, and a calculation done in a function, this function should then return the value to my sub?
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim i As Integer = 1
Test_function(i)
MsgBox(i)
End Sub
Private Function Test_function(ByVal i As Integer)
i = i + 1
Return (i)
End Function
When i run this piece of code I get:
i = 1 in sub
i = 2 in function
i = 1 in sub?
How do you get the i = 2 into my sub? Or is this not the correct way of using this?
I think what you're asking is why does i not get changed by the call to Test_function.
Let's break down your code.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim i As Integer = 1 'creating a variable named i, value 1.
Test_function(i) 'passing the value of the variable i to test function, but not doing anything with what the function returns.
MsgBox(i) 'calling messagebox with the value i.
End Sub
Private Function Test_function(ByVal i As Integer) 'creating a new variable also named i with the value being passed in.
i = i + 1 'incrementing the value of the i variable by 1.
Return (i) 'returning i
End Function
So there are a few concepts that you're misunderstanding as far as I can tell- what ByVal means, perhaps the concept of variable scoping, as well as what Return does.
The obvious answer is that you're not using the value returned by Test_function. If you had i = test_Function(i), then i would be incremented by the call to Test_function
Another approach would be to pass i ByRef instead of ByVal- if you did that, the i in the scope of your Test_function method would be the same as the i in the scope of your Button1_Click method. But because you are passing it ByVal, the i variables are actually two completely different variables.
There is nothing to wonder, it's only a simple misunderstanding. you are printing the actual value of i if you Call like this:
MsgBox(Test_function(i))
Then both will be the same;
or you can check this in following way:
Dim tempVal = Test_function(i)'<-- will give 2
MsgBox(i)'<--- will give 1
this is because you are passing the value of i not i as reference, if you pass it as reference then also both will be the same.
So if you change the function signature as follows:
Private Function Test_function(ByRef i As Integer)
i = i + 1
Return (i)
End Function
same function call will give you both values as 2
Dim tempVal = Test_function(i)'<-- will give 2
MsgBox(i)'<--- will give 2
Reference ByVal and ByRef
Frm1 contains the code for validation of textbox:
Public Function AlphabeticalOnly(ByVal Str As String) As Boolean
Dim pattern As String = "^[a-zA-Z\s]+$"
Dim reg As New Regex(pattern)
If reg.IsMatch(Str) = False Then
MsgBox(Str & " is invalid! Please enter alphabetical characters only!", MsgBoxStyle.Critical, "Error")
End If
Return reg.IsMatch(Str)
End Function
Because there're quite an amount of validations, I don't want to repeat all the code again in the other forms.
Private Sub btnDone_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDone.Click
If AlphabeticalOnly(txtName.Text) = False Then
Exit Sub
End If
...
End Sub
I tried the code above in another form, but the error list shows that AlphabeticalOnly is not declared.
Is there anything that I need to add to my code?
First of all, don't put the function on a form. If it's common code shared by all forms, put it in its own class file.
Second, this common code shouldn't be prompting the user with a message box. This function should just perform the logic and nothing more. (This also makes the function easier to unit test.) Then allow the consuming code (in this case a form) to interact with the user. (Especially since the current implementation checks the match twice, which isn't necessary.)
Since this function doesn't rely on object state, you can make it Shared. Something like this:
Public Class CommonFunctions
Public Shared Function IsAlphabeticalOnly(ByVal Str As String) As Boolean
Dim pattern As String = "^[a-zA-Z\s]+$"
Dim reg As New Regex(pattern)
Return reg.IsMatch(Str)
End Function
End Class
Then on your forms you can invoke that function:
If CommonFunctions.IsAlphabeticalOnly(txtName.Text) = False Then
MsgBox(Str & " is invalid! Please enter alphabetical characters only!", MsgBoxStyle.Critical, "Error")
End If
What is the difference between doing this:
Public Sub MySub(ByVal MyString as String)
Dim TheString as String = MyString
myFunction(TheString)
'Some more code...
End Sub
Compared to this:
Public Sub MySub(ByVal MyString as String)
MyFunction(MyString)
'Some more code
End Sub
That is, is there a good reason to dimension a variable in a function/sub again before using it from the argument line? Or does it not matter?
Hope this makes sense, I wasn't sure how to word this question.
If it's a value based Type (e.g: string or integer, double etc.), unless it's passed using the reference (ByRef) instead of the value (ByVal), you shouldn't need to worry about storing it in another variable (unless you wish to have 2 copies)
If the function required a modified string, so you were changing it to fit that, the first code block would make some sense.
However--since it's equal, the only case I can think of you needing the first block of code is if you're needing to keep myString the same within that sub...but I would think if you were doing something like that, most of the time you would just have a totally different sub.
Because you used ByVal-- once you exit that sub, myString will once again be whatever it was initially set to before you entered the sub, because the mystring you're working with inside of the sub is just a copy of the value.
In contrast, if you used ByRef the changes made to the variable would be taken back to the main code and actually change the value of mystring.
You can read about the difference between ByVal and ByRef here: http://social.msdn.microsoft.com/Forums/vstudio/en-US/07b9d3b9-5658-49ed-9218-005564e8209e/what-is-the-difference-between-byval-and-byref
You can take all these concepts and play with how it works in a simple console program to further your understanding. That's what I did, here's some of the code I toyed with to double check what I was saying. Try changing where ByVal & ByRef is used, and maybe printing to the screen after you make a change to see what sticks and what doesn't.
Sub Main()
Dim someString As String = "This is some string."
MySub(someString)
Console.WriteLine(someString)
MyOtherSub(someString)
Console.WriteLine(someString)
Console.ReadLine()
End Sub
Public Sub MySub(ByVal myString As String)
Dim theString As String = myString
MyFunction(theString)
' First line printed in console.
Console.WriteLine(theString)
theString = "Hello."
Console.WriteLine(theString)
Console.WriteLine(myString)
myString = "I'm mystring."
Console.WriteLine(myString)
End Sub
Public Sub MyOtherSub(ByVal MyString As String)
MyFunction(MyString)
End Sub
Public Function MyFunction(ByRef mystring As String)
mystring += "myFunction is acting on this string."
End Function