No more answers please, the problem was solved. Skip to the end of the question to see what i have done wrong.
I am running the following Functionto read the syntax of a specific standard either by FilePath (Function reads the file first to get the string) or by the Text itself (skips file reading)
Public Function ReadStandard(Optional ByVal FilePath As String = Nothing, _
Optional ByVal Standard_Text As String = Nothing) As Boolean
to make this possible only one of those parameter must be set, while the other must not be set. I do not want to use a function like
Public Function ReadStandard(str as String, isFilePath as Booelean) As Boolean
So to make this possible I want to use Xor, since it should do the exact job
(if you pass 2 Booleans to XOR it should only return True, when A != B). Doing some research i found that this works in vb.net: MSDN
But for some reason it doesn't work for me;
If IsNothing(FilePath) Xor IsNothing(Standard_Text) Then (...)
Is there a reason for it? Or did I forget what i learned back in the days?
Turns out that I just mixed something up in my logic. In the following function I forgot to put the Not into the If-Statement
If Not (IsNothing(FilePath) Xor IsNothing(Standard_Text)) Then
Throw New ArgumentException("FilePath or Standard_Text must be set.")
Return False
End If
XOR can be thought of as binary addition without carry.
If False Xor False Then '0+0
Stop
End If
If True Xor False Then '1+0
Stop
End If
If False Xor True Then '0+1
Stop
End If
If True Xor True Then '1+1
Stop
End If
how does your call look like? I tried your sample and it is working.
Public Function ReadStandard(Optional FilePath As String = Nothing, Optional Standard_Text As String = Nothing) As Boolean
ReadStandard = False
If IsNothing(FilePath) Xor IsNothing(Standard_Text) Then
ReadStandard = True
End If
End Function
Calling like this (X is example path) delivers the right answer:
ReadStandard(,) --> False
ReadStandard(, "X") --> True
ReadStandard("X",) --> True
ReadStandard("X", "X") --> False
Be aware of calling like ReadStandard("", "X"), because that means FilePath is not empty.
BR
Related
I want to design a Function or Sub that accepts any number of boolean conditions and add them to an IF statement. The code i imagine goes like this:
Function comp (ParamArray list() As Variant)
If (list(0) = True) And (list(1) = true) ..... (list(last) = true) then
'random code
End If
End Function
where list() would be expresions like:
x = y-1,somethingToCompare <> anotherThing, etc...
It would be interesting if i could add the "and" as another argument, to be changed to "or" if i wished to.
Function comp (VyVal compare as Boolean, ParamArray list() As Variant)
dim comparison as String???
If compare then
comparison = "and"
else
comparison = "or"
end if
If (list(0) = True) comparison (list(1) = true) ..... (list(last) = true) then
'random code
End If
End Function
The final idea is to use that function like this:
Sub code ()
if comp(True, condition1, condition2, ...) then
'random code'
End Sub
Avoid directly looking at that code i wrote lest it burn your eyes.
Is something like this posible or should i get a lollipop?
Maybe i'm looking at this in the wrong way, and there's an easier way of doing something similar or even better.
Python (and some other languages) has useful functions all() and any() which take as input an array (or some other iterable) of Booleans and returns either True or False depending on whether or not some, all, or none of the passed Booleans are True. You could write VBA versions of these (using Some() instead of Any() since Any happens to be a somewhat obscure keyword in VBA):
Function All(ParamArray conditions()) As Boolean
Dim i As Long
For i = LBound(conditions) To UBound(conditions)
If Not conditions(i) Then
All = False
Exit Function
End If
Next i
All = True
End Function
Function Some(ParamArray conditions()) As Boolean
Dim i As Long
For i = LBound(conditions) To UBound(conditions)
If conditions(i) Then
Some = True
Exit Function
End If
Next i
Some = False
End Function
You could use these functions directly to conditionally call code.
Arguably it might be more useful to change the above definitions to:
Function All(conditions As Variant) As Boolean
Dim i As Long
For i = LBound(conditions) To UBound(conditions)
If Not conditions(i) Then
All = False
Exit Function
End If
Next i
All = True
End Function
Function Some(conditions As Variant) As Boolean
Dim i As Long
For i = LBound(conditions) To UBound(conditions)
If conditions(i) Then
Some = True
Exit Function
End If
Next i
Some = False
End Function
Now you would need to use calls like Some(Array(c1, c2, c3)) rather than Some(c1,c2,c3) if you had a literal list of conditions, but you would have the flexibility to pass in an entire array of conditions. Using this second definition you could write something like the following (which answers your original question):
Sub Sometimes(when As String, ParamArray conditions())
Dim run As Boolean
Dim cond As Variant
cond = conditions
run = IIf(when = "All", All(cond), Some(cond))
If run Then
Debug.Print "Running random code"
Else
Debug.Print "Not running random code"
End If
End Sub
Then, for example, Sometimes "Some",True,True,False results in Running random code being printed.
sub pointless(byval IsAnd as boolean, paramarray conditions())
dim i as long
for i=lbound(conditions) to ubound(conditions)
if IsAnd then
if not conditions(i) then exit sub
else
if conditions(i) then exit for
end if
next
'random code
end sub
But you should realise that the procedure will receive results of the comparisons passed to it, not the comparisons themselves. So there is no point really to have such procedure in the first place, you can just write directly in your code:
if x = y-1 and somethingToCompare <> anotherThing then
'random code
end if
I have a VBA class that contains a number of variants. These variants are there to hold Y x Z size arrays, but they're optional inputs (and so often the variants will never get used or initialized).
A function within the same class calls on each of these variants to perform a calculation. BUT, I need it to skip the variants that are blank. When I try to use IsNull(xyz) and IsEmpty(xyz), both return false. Looking at the watch on xyz, it has:
Expression: xyz
Value:
Type: Variant/Variant()
Context: className
Totally blank under value.
Any ideas how I can test/return a boolean if these things are empty? Or even a boolean if they're full, that would work too.
Thanks
Edit: I should add, that IsMissing just completely crashes excel...
Very dirty workaround but something like this might do the trick:
Function IsEmptyArray(testArr As Variant) As Boolean
Dim test As Long
Dim ret As Boolean
ret = False
On Error Resume Next
test = UBound(testArr)
If Err.Number = 9 Then
ret = True
End If
Err.Clear
On Error GoTo 0
IsEmptyArray = ret
End Function
One method I've used in the past is to test whether or not the array is filled using a helper function. I join the array using an empty string delimiter and test that the length is greater than zero. It has worked in my circumstances, but I'm not sure if there are any flaws in the logic.
Below code returns true if the array is empty and false if it is not:
Function TestIfArrayIsEmpty(vArray As Variant) As Boolean
TestIfArrayIsEmpty = (Len(Join(vArray, "")) = 0)
End Function
You can use vartype(variable_name. You can check
vartype(varriable_name) = vbArray or VbEmpty or VbNull
Then check LBound and UBound of eac dimension
for example
LBound(variable, 1) and UBound(variable_name, 1) to check the lower and higher indexes of the array.
I know the statement String.IsNullOrEmpty which I use regulary.
But now I'm wondering if I could use something similar for Dictionaries
My Current Code:
Public Property ExpectedResults As Generic.Dictionary(Of String, String)
Public Function SomeMethod() As Boolean
'Some code
If (IsNothing(ExpectedResults)) Then
Return True
End If
If ExpectedResults.Count = 0 Then
Return True
End If
For Each key As String In ExpectedResults.Keys
'If Regex Matches value
Return True
'End If
Next
Return False
End Sub
Is it possible to replace those 2 Ifs with 1 single statement? Or am I searching for something that doesn't exist?
Thank you for your time.
If I understand correctly, You want to check if your Dictionary is NOT nothing and also contains items? In this case I would go with
If Not IsNothing(ExpectedResults) AndAlso ExpectedResults.Count > 0 Then
Return True
End If
The null-conditional operator makes it pretty tidy:
If ExpectedResults?.Count > 0 Then
Return True
End If
The obvious first thought is:
Public Function CheckStrings(ByVal input As String()) As Boolean
For Each s As String In input
If s.Length > 0 Then Return True
Next
Return False
End Function
I'm sure there is a simpler way than that though. At least simpler in terms of the code if not necessarily the performance.
End result:
Well, you guys did a pretty good job of simplifying. Well done.
I think I'll still use an extension to make it just that much simpler in the main code. The final result really isn't too bad by itself though.
Here's my final code:
<Extension()> _
Public Function AnyNonZero(ByVal value As String()) As Boolean
If Not value.All(Function(x) String.IsNullOrEmpty(x)) Then Return True
Return False
End Function
You can use this to return true if all elements are zero length.
Dim inputIsEmpty As Boolean = Array.TrueForAll(input, Function(x) x.Length = 0)
Be careful of null references. You may want to use this instead:
Dim inputIsEmpty As Boolean = Array.TrueForAll(input, Function(x) String.IsNullOrEmpty(x))
How about this? It uses your string array named input.
Array.TrueForAll(input, AddressOf ZeroLengthString)
Private Function ZeroLengthString(ByVal s As String) As Boolean
Return s.Length = 0
End Function
Here's a Linq function similar to Array.TrueForAll:
Dim allEmpty = values.All(Function(x) x.Length = 0)
I find it to be a bit more easily readable than Array.TrueForAll.
I call a function (SaveChanges) to access my business / data layer and save any changes to fields that are marked as an Add or Update and are marked to be processed. This function used to work fine up until 60+ minutes ago.
What is happening is that suddenly the function is returning false. After debugging through the code, when it hits Return the local boolean is set as True ... but when it gets back to the calling method (and uses the return value) it is now False.
As I said I went through line by line and debugged it, then I added a watch to it. The funny part is that there is one spot that sets the boolean to false, and when I put a breakpoint on that spot it is never reached.
Here is the function:
Private Function SaveChanges() As Boolean
Dim blnSaved As Boolean = True
Dim saveableRows As List(Of DataRow) = (From d As DataRow In _listData.Tables(0).Rows _
Where Not d("Marking") = "Duplicate" _
And d("Process") = True _
Select d).ToList()
If saveableRows.Count > 0 Then
For Each drRow As DataRow In saveableRows
Dim data As IDataEntity = DataEntities.GetData(_tableName)
If drRow("Marking") = "Update" Then
'UPDATE
data.UpdateItem(drRow.ItemArray)
Else
'ADD
data.AddItem(drRow.ItemArray)
End If
If data.HasErrors Then
blnSaved = False 'Never reaches this part ... !?!?!
End If
Next
Else
blnSaved = True
End If
End Function
And here is how I'm using the function:
If SaveChanges() Then
Dim frmTableView As frmTableView = New frmTableView(_listData.Tables(0).TableName)
If Not Me.MdiParent Is Nothing Then
frmTableView.MdiParent = Me.MdiParent
End If
frmTableView.Show()
Me.Close()
Else
MessageBox.Show("Unable to save the list. IT has been notified.", "Save Failed", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
I'm spending too much time on this and figured it was time to look for help.
Thanks
You're never returning your boolean. Add:
Return blnSaved
at the bottom of the function.
You never assign the function return value. You'll get its default value, False. Instead of assigning to the local variable (blnSaved), assign to SaveChanges instead. Or add Return blnSaved at the end of the function.
Aren't you just missing a Return blnSaved at the end of your function?
I agree that you are simply missing Return blnSaved statement. I would also suggest that you do not need the following else statement because you are already initializing the blnSaved value at the start of the method.
Else
blnSaved = True
End If