I have to create a class in Visual Basic called StringWork.
Public Class StringWork
Now i wrote a shared function in the class called Working that can take a string or a string and Boolean.
Public Shared Function Working(ByVal SingleString as string, optional BValu as Boolean = true)as string
if(working(SingleString))then
'The handling of the string
else if (working(SingleValue, BValue) then
'do something else with string
end if
end function
The function I wrote is returning a string.
Can I access the string passed and edit characters in the string or change the position of characters?
You use that optional parameter to determine how you handle that string:
Public Shared Function Working(ByVal singleString as string, _
Optional bValue as Boolean = True) As String
If bValue Then
'Handle the true part manipulating the result string
Else
'Handle the false part manipulating the result string
End If
End Function
If you call this function like this:
Dim test As String = StringWork.Working("I am Spartacus")
it will call that Working function with bValue = true.
What bValue is suppose to represent isn't very clear from the code nor the post.
In VB.NET, and other .NET languages, strings are immutable. Typically, if you need to modify a string that is passed to your method, you would return the modified string. If however, you need it to modify the parameter, you can specify that it is a "ByRef" argument, in which case you will be able to set it to point to a new string object which will affect the variable that was passed into the method as a parameter. If you need a truly mutable string, you will need a character array or a StringBuilder object.
Related
I am using a function to modify a series of strings, passing them ByRef as arguments to the modifying function. The caller's string variables are all modified as expected but the one argument which is a class property does not change, should this be possible?
The essentials of the class are:-
Private cRptRef As String
Public Property Get TestRefID() As String
TestRefID = cRptRef
End Property
Public Property Let TestRefID(Test_Ref As String)
cRptRef = Test_Ref
End Property
The function for modifying the strings has the following declaration
Public Function GetTestFileNames(ByRef hdrFile As String, _
ByRef calFile As String, _
ByRef dataFile As String, _
ByRef testRef As String _
) As Boolean
The call to GetTestFilenames is as follows:
If GetTestFileNames(HEADERpath, CALpath, RAWDATApath, _
ref) = False Then
All the string arguments are declared as global strings and are empty ("") before the call. After the call they typicaly have content like "d:{path to file{filename.csv}.
So all these statements in the function populate the target strings OK.
hdrFile = Replace(userFile, "##", PT_Rpt.Info.FindNode(TEST_REF_HDRsuffix).data, , , vbTextCompare)
dataFile = Replace(userFile, "##", PT_Rpt.Info.FindNode(TEST_REF_DATAsuffix).data, , , vbTextCompare)
calFile = Replace(userFile, "##", PT_Rpt.Info.FindNode(TEST_REF_CALsuffix).data, , , vbTextCompare)
But this statement fails to assign anything to its target string
testRef = Mid(userFile, InStrRev(userFile, Application.PathSeparator) + 1)
testRef = Left(testRef, InStrRev(testRef, "_") - 1)
Debug.Print "Class.TestRefID="; testRef
The Debug.Print statement prints the expected string, but the external reference is not affected. Is this something to do with it being a property?
The target string being Class.TestRefID in place of the testRef argument.
If I replace the class property in the argument list with a standard string variable, and then assign that to the class property then it I get the expected result, which seems unnecessary work.
Is there something I'm missing or is this not possible in VBA?
A member access expression is an expression that must first be evaluated by VBA before its result can be passed around.
If I have a Class1 module like this:
Option Explicit
Public Foo As String
And then a quick caller procedure:
Sub test()
With New Class1
bla .Foo
Debug.Print .Foo
End With
End Sub
Sub bla(ByRef bar As String)
bar = "huh"
End Sub
The test procedure will output an empty string.
The reason for this is because when you pass a member to a ByRef parameter of a procedure in VBA, you're not passing a reference to the member - you're passing a reference to the value held by that member.
So the member access expression is evaluated, evaluates to "", so "" is passed ByRef to the procedure, which assigns it to "huh", but the caller isn't holding a reference to the "" value, so it never gets to see the "huh" string that was assigned.
If I replace the class property in the argument list with a standard string variable, and then assign that to the class property then it I get the expected result, which seems unnecessary work
It's not unnecessary work, it's mandated, otherwise nothing is holding a reference to the result of the member expression.
Then again the real problem is a design issue, pointed out by Warcupine: the function doesn't want to byref-return 4 values, it wants to take a reference to this object, and assign its properties.
I encountered an issue with Function and Procedure while experimenting with some code, as below:
Module mod1
Class ExampleApp
Dim textvalue as String = "dGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgdGV4dC4="
Dim string1 as String = "Convert.FromBase64String(input)"
Public Function DecodeB64(ByVal input As String) As String
Return System.Text.Encoding.UTF8.GetString(string1)
End Function
End Class
End Module
The question is, is it possible to encode the statement inside the Public Function before it gets executed?
I have seen some cases where they implemented it on PHP Scripts, where the whole script is encoded before it gets executed. I have tried my best in applying the same concept by storing "Convert.FromBase64String(input)" to a string variable but I'm encountering an issue like this:
Value of type 'String' cannot be converted to '1-Dimensional array of
Byte'
When I don't apply this concept, the text in base64 gets decoded smoothly. My main goal is that I want to obscure the statement or group of statements as much as possible. What seems to be the problem in this Error?
You have 2 mistakes below in the example code:
First, you should know that Convert.FromBase64String() returns
Byte() array, hence you can't assign it to string variable/field.
Second, Encoding.GetString() requires Byte() array as parameter,
but you're passing string to it, hence InvalidCastException occurred.
The correct usage of them should be like this:
Public Function DecodeB64(ByVal input As String) As String
' make sure the input string is Base64 formatted
Dim bytearray As Byte() = Convert.FromBase64String(input)
' decoding from byte array
Return System.Text.Encoding.UTF8.GetString(bytearray)
End Function
' usage
Dim textvalue as String = "dGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgdGV4dC4="
Dim result As String = DecodeB64(textvalue)
Working example: .NET Fiddle demo
I have some simple code and I understand what it does but not why. I have a Sub and it calls another Sub called CheckIfNothing(oList). oList is a List(Of String). The Sub CheckIfNothing checks each String and if it it Nothing it will make it "". This is the code:
Public Function GiveList(oList As List(Of String))
CheckIfNothing(oList)
Return oList
End Function
Public Sub CheckIfNothing(oList As List(Of String))
For Each s As String In oList
If s Is Nothing Then
s = ""
End If
Next
End Sub
So in GiveList I call CheckIfNothing and I don't return anything from CheckIfNothing and still, the oList in GiveList has no Strings that are Nothing.
I always thought you had to return the value you changed in the called function and set the value again in the sub you call the function in like this: oList = CheckIfNothing(oList). CheckIfNothing would be a function in this case.
Why isn't this necessary, and is this only in VB.NET or also the case in C#?
Maybe this will help explain your question. It is from MSDN regarding Visaul Basic 2013.
When passing an argument to a procedure, be aware of several different distinctions that interact with each other:
•Whether the underlying programming element is modifiable or nonmodifiable
•Whether the argument itself is modifiable or nonmodifiable
•Whether the argument is being passed by value or by reference
•Whether the argument data type is a value type or a reference type
For more information, see Differences Between Modifiable and Nonmodifiable Arguments (Visual Basic) and Differences Between Passing an Argument By Value and By Reference (Visual Basic).
This code is an example of how you can use () around your parameter to protect it from being changed.
Sub setNewString(ByRef inString As String)
inString = "This is a new value for the inString argument."
MsgBox(inString)
End Sub
Dim str As String = "Cannot be replaced if passed ByVal"
' The following call passes str ByVal even though it is declared ByRef.
Call setNewString((str))
' The parentheses around str protect it from change.
MsgBox(str)
' The following call allows str to be passed ByRef as declared.
Call setNewString(str)
' Variable str is not protected from change.
MsgBox(str)
Passing Arguments by Value and by Reference (Visual Basic) 2013
I have an html helper class for my webforms projects. so far it can return strings to create labels and readonly fields.
Public Shared Function DisplayFor(value As String, Optional attributes As String = "") As String
Return [String].Format("<span class='uneditable-input {0}'>{1}</span>", GetSStyle(attributes), value)
End Function
Now I want to create some overloads that can accept passing the entity property so it can internally check the datatype (from attributes) and display the content formatted, for example. Just as MVC does.
The only problem it's that I don't know how to pass a class property as a function parameter.
You can pass a property as an Expression(Of Func(Of MyModel, String)) and by that receive an expression in the method that you can analyze and evaluate:
Public Shared Function DisplayFor(Of TModel, TValue)(model As TModel, expr As Expression(Of Func(Of TModel, TValue))) As String
' Retrieve the value dynamically
Dim compExpr = expr.Compile()
Dim value = compExpr.DynamicInvoke(model)
Dim retVal As String
If value Is Nothing Then
retVal = String.Empty
Else
retVal = value.ToString()
End If
' Analyze expression body
Dim memberAccExpr = DirectCast(expr.Body,
System.Linq.Expressions.MemberAccessExpression)
Dim attr = memberAccExpr.Member.GetCustomAttributes(typeof(MyDisplayAttribute), false).Cast(Of MyDisplayAttribute)().FirstOrDefault();
Return retVal
End Function
Call the method like this:
DisplayFor(myModelVar, Function(m) m.MyProperty)
I hope this sample gives you a rough outline on how to handle this. Please note that especially the analysis of the expression body is simplified. In real world code there would be various checks to make sure that the expression matches your expectations.
I know strings are immutable, so the minute you change a string reference's value .NET makes a brand new string on the heap.
But what if you don't change the value of a string reference; rather, you simply pass it into a function ByVal -- does this operation copy the string value on the heap as well? My inclination is "no," but I'd like to confirm.
For example:
Public Function IsStringHello(ByVal test As String) As Boolean
Return (String.Compare(test, "Hello") = 0)
End Function
Calling program:
Dim myWord as String = "Blah"
Dim matchesHello as Boolean = IsStringHello(myWord)
I know passing myWord by value makes a copy of the reference to "Blah", but since I have not tried to change the string itself, would it make another copy of the string on the heap?
By the way, string interning is completely unrelated to that. The rule for passing parameters to functions is the same for all reference types (and really, all types), no matter how they are managed internally.
The rule is simple and you have stated it correctly: pass by value copies the reference, not the target. No heap space is copied here.
No. it still uses the copy of the reference to the "Blah".
What makes you think, it will?
On a side note, string are interned.
string s = "hello";
string t = "hello";
s & t both refer to the same string (because it is interned). If you modify s or t, it will create a new string, then.
Passing objects ByVal creates a copy of the pointer, not the object itself. Here's a demonstration:
Module Module1
Dim original As String = "Hello world"
Sub PassByReferenceTest(ByVal other As String)
Console.WriteLine("object.ReferenceEquals(original, other): {0}", _
Object.ReferenceEquals(original, other))
End Sub
Sub Main()
PassByReferenceTest(original)
Console.ReadKey(True)
End Sub
End Module
This program outputs the following:
object.ReferenceEquals(original, other): True
So, the original string and the string we passed by value exist at the same address in memory address. You're not making a copy of the string itself.
Is short, no. It passes a ref to the string. Only one instance of the string itself.
string is a reference type. If you pass it by value, what you are passing is the value of the reference.
The only way you'd get another copy on the heap would be to change the variable's value.
A variable of type System.String effectively holds an "object-ID". Suppose that Object #1934 is a string with the characters "Blah", and you say Dim myWord As String = "Blah". The compiler will then store Object #1934 into myWord. Calling IsStringHello(myWord) would then cause that function to be called with its test parameter equal to Object #1934. In your example, there would be two variables of type System.String in memory--myWord and test, and both would hold the content Object #1934.